Converting This Site From Jekyll to Astro
For a few years, this site was a Jekyll blog using the kiko-now theme - a minimal, one-click GitHub Pages setup that was perfect for getting something live without fussing over infrastructure. You fork the repo, drop some markdown files in _posts/, and GitHub Pages builds and serves it automatically. It’s honestly a great setup if you just want to write.
So why change it? Mostly restlessness, and a genuine curiosity about Astro. I’d been hearing good things and wanted a reason to actually use it. Rebuilding a personal site is a low-stakes way to learn a new tool, and I figured the migration would be instructive even if the end result looked similar.
What I Was Leaving Behind
The kiko-now theme is clean and does exactly what it promises. The site loaded fast, the typography was readable, and the GitHub Pages deployment pipeline was invisible - push to main, site updates in under a minute. Hard to complain.
The limitation wasn’t the theme, it was Jekyll itself. The Ruby toolchain is a pain to set up locally if you’re not already in that ecosystem. Every time I came back to the site after a few months away, I’d spend twenty minutes fighting bundler version mismatches before I could preview anything. It’s a minor complaint but it was enough friction to make me avoid touching the site at all.
Why Astro
Astro felt like a natural fit for a content-heavy site. The core idea - ship zero JavaScript by default, render everything to static HTML at build time - is exactly right for a site that’s mostly text. There’s no reason for a blog to be hydrating a React component tree in the browser.
The content collections API is particularly nice. You define a schema for your markdown frontmatter with Zod, and Astro validates it at build time. No more silently broken posts because you forgot the date field or misspelled a key. The TypeScript integration means you get autocomplete on your post metadata throughout the codebase, which feels like overkill for a personal site but is pleasant nonetheless.
The file-based routing also just made sense to me. src/pages/writing/[id].astro is a dynamic route that generates a page for each post - readable, obvious, no configuration required.
The Migration
The actual content migration was trivial. Jekyll posts live in _posts/ with filenames like 2017-06-01-brief-primer-on-compilers.md, and the frontmatter format is nearly identical to what Astro expects. It was mostly a find-and-replace job to strip out Jekyll-specific liquid template tags and consolidate the frontmatter fields.
The bigger lift was building the layout and styling from scratch rather than inheriting them from kiko-now. I didn’t want to just port the old theme over - if I was rebuilding, I wanted it to actually look like mine. That meant writing the CSS myself, which took longer than the content migration but was more satisfying.
One genuinely nice thing about Astro: the <style> blocks in .astro files are scoped by default. No class name collisions, no BEM conventions required, no CSS modules to configure. You just write styles and they apply to that component. It makes the CSS feel much less like a minefield.
Switching to Cloudflare Pages
I’d been on GitHub Pages since the beginning. It works fine, but it’s limited - no custom redirect rules, no edge caching configuration, build times that can feel sluggish for larger sites. Cloudflare Pages addressed all of that and has a generous free tier.
The setup was straightforward: connect the GitHub repo, tell Cloudflare the build command (npm run build) and the output directory (dist/), and it handles the rest. Deployments are fast - Astro’s build is quick and Cloudflare’s CDN picks up the new files almost immediately. I also get preview deployments on every pull request automatically, which is a nice bonus for a solo project where I sometimes want to sanity check something on my phone before merging.
The other thing Cloudflare gives you is analytics without the privacy implications of Google Analytics. Basic page view data, no cookies, no tracking scripts. Good enough for a personal site.
Was It Worth It
Honestly, for pure functionality, the old setup was fine. The new one doesn’t do anything the old one couldn’t. But the local dev experience is night and day - npm run dev just works, every time, no dependency archaeology required. And having a codebase that I actually understand end-to-end, rather than a theme I inherited and never fully read, makes me more likely to actually maintain it.