Migrating My Personal Site from Jekyll to Astro

Khaled Zaky ·

It had been years since I last touched my personal website. The site was running on Jekyll, a Ruby-based static site generator that served me well since 2017. But the world of web development has moved on, and so have my needs. This post walks through why I decided to migrate, how I did it, what improved, and what’s coming next.

Why Migrate?

The honest answer: friction. Every time I wanted to write a new post, I had to remember how to set up my Ruby environment, deal with Bundler dependencies, and work with Liquid templates that I hadn’t touched in years. The cognitive overhead of getting back into “writing mode” was high enough that I simply… didn’t write.

Here’s what was bothering me:

  • Ruby dependency managementbundle install failures, version conflicts, and the overhead of maintaining a Ruby environment just for a blog
  • Liquid templating — Powerful but verbose. Every layout change required navigating a maze of _includes and _layouts with Liquid tags
  • No component model — Want to reuse a piece of UI? Copy-paste HTML across includes. No props, no composition
  • Styling — The site used Sass with a custom framework. Making design changes meant diving into deeply nested SCSS files
  • Build speed — Jekyll builds were getting slower as the site grew, and the Ruby toolchain added overhead to the CI/CD pipeline

I needed something modern, fast, and low-friction enough that I’d actually use it.

Why Astro?

I evaluated a few options — Next.js, Hugo, Eleventy, and Astro. Here’s why Astro won:

  • Markdown-first — Astro’s Content Collections give you typed, validated Markdown with zero config. Perfect for a blog
  • Component islands — Write components in .astro files with a clean, HTML-like syntax. No JavaScript shipped to the client unless you explicitly opt in
  • Tailwind CSS integration — First-class support via @astrojs/tailwind. No more managing Sass toolchains
  • Static by default — Astro generates pure static HTML. No hydration, no runtime. Exactly what a blog needs
  • Fast builds — The Astro build for this site completes in under 1 second. Jekyll was taking 5-8 seconds
  • Node.js ecosystem — npm, not Bundler. A toolchain I use every day

The Migration Process

The migration took a single afternoon with the help of Windsurf, Codeium’s agentic IDE. Here’s the high-level approach:

1. Scaffold the Astro Project

I created the Astro config, Tailwind setup, and content schema alongside the existing Jekyll files. This meant I could build and test the new site without breaking the old one.

Key files created:

  • astro.config.mjs — Site URL, integrations (MDX, Sitemap, Tailwind)
  • tailwind.config.mjs — Custom color palette, typography plugin, dark mode
  • src/content/config.ts — Content collection schema defining frontmatter types

2. Build Layouts and Pages

I replaced Jekyll’s _layouts and _includes system with Astro components:

JekyllAstro
_layouts/home.html + _includes/head.html + _includes/header/home.html + _includes/footer.html + _includes/closing-tags.htmlsrc/layouts/BaseLayout.astro
_layouts/blogpost.htmlsrc/layouts/BlogPost.astro
_includes/header/*.htmlsrc/components/Header.astro
_includes/footer.htmlsrc/components/Footer.astro

The Astro component model is dramatically simpler. A layout is just an .astro file with a <slot /> for content. Props are typed. No more Liquid variable gymnastics.

3. Migrate 14 Blog Posts

Each Jekyll post had frontmatter like:

---
layout: blogpost
title: "What is Cloud?"
date: 2017-05-27 12:00:00
author: "Khaled Zaky"
categories: cloud
---

For Astro, I converted them to:

---
title: "What is Cloud?"
date: 2017-05-27
author: "Khaled Zaky"
categories: ["cloud"]
description: "An overview of cloud computing..."
---

Key changes: removed layout (handled by the page template), converted space-separated categories to arrays, added description for SEO, and moved files from _posts/ to src/content/blog/.

4. Update the Build Pipeline

The buildspec.yml for AWS CodeBuild went from:

# Before (Jekyll)
- gem install bundler
- bundle install
- bundle exec jekyll build
- aws s3 sync _site/ s3://khaledzaky.com

To:

# After (Astro)
- npm ci
- npm run build
- aws s3 sync dist/ s3://khaledzaky.com

Simpler, faster, and no Ruby runtime needed. The CodeBuild image just needs Node.js 20.

5. Redesign with Tailwind CSS

While migrating, I took the opportunity to redesign the site with a minimal, modern aesthetic:

  • Dark/light mode with system preference detection and a toggle
  • Clean typography using Inter for body text and Lora for headings via @tailwindcss/typography
  • Responsive layout that works well on mobile
  • Category filtering on the blog index
  • Posts grouped by year for easy scanning

Measured Improvements

MetricJekyllAstroImprovement
Local build time~5-8s<1s~8x faster
CI/CD build time~45s (Ruby install + build)~15s (npm ci + build)~3x faster
DependenciesRuby + Bundler + 6 gemsNode.js + npmSimpler toolchain
Layout files4 layouts + 12 includes2 layouts + 2 components75% fewer files
StylingCustom Sass framework (12 files)Tailwind CSS (1 config + 1 global CSS)90% fewer style files
Output size~3.4 MB~3.4 MBSimilar (content-driven)

The biggest win isn’t in the numbers — it’s in developer experience. I can now spin up the dev server with npm run dev, edit a Markdown file, and see changes instantly. No Ruby environment, no Bundler, no waiting.

Tooling

This migration was done using:

What’s Next: An AI Blog-Writing Agent

As part of this migration, I also built an AI blog-writing agent that lives in the agent/ directory of this repo. It uses:

  • Amazon Bedrock (Claude) for research and drafting
  • AWS Step Functions to orchestrate the pipeline
  • Amazon SNS for human-in-the-loop email notifications
  • GitHub API to commit approved posts, triggering auto-deploy

The workflow: I give it a topic → it researches → drafts a post → emails me for review → I approve → it commits to GitHub → CodeBuild deploys. I’ll write more about this in a future post.

Final Thoughts

If you’re running a Jekyll blog and feeling the friction, I’d highly recommend looking at Astro. The migration path is straightforward — your Markdown content moves over almost unchanged, and you get a dramatically better developer experience in return.

The best framework is the one that gets out of your way and lets you focus on writing. For me, that’s now Astro.