IF you've been here before, you might notice things look a bit different now. I changed jobs, moved countries, started fresh. And oh yeah, the site's got a fresh coat of dark mode by default, cleaner design and under the hood, I've ditched Jekyll for Eleventy (11ty). Here's how I pulled it off.

Why Leave Jekyll?

I've been using Jekyll for a while now. It's what powered this site from the start. It's solid for static sites, especially if you're in the Ruby ecosystem or hosting on GitHub Pages. But as I evolved, a few pain points started to add up:

  • Ruby Dependency Hell: Jekyll runs on Ruby, and managing gems, versions, and dependencies can be a hassle, especially on macOS where Ruby updates break things. I wanted something in Node.js, which I'm way more comfortable with and it's easy to troubleshoot.

  • Build Times and Flexibility: Eleventy is known for being lightning-fast and super flexible. You can use Nunjucks, Liquid, or even mix templates. Plus, it's just JavaScript, so customizing filters, shortcodes, and plugins was easier.

  • Modern Features Out of the Box: I needed to implement dark mode natively and make the design cleaner without hacking too much CSS. Eleventy made it easier to integrate modern tooling, and I could keep the structure similar while tweaking the aesthetics.

Don't get me wrong, Jekyll served me quite well, but it was time.

Migration Blueprint

After a lot of local testing and polling AI for workarounds, below's a step-by-step I followed.

Step 1: Set Up Eleventy

First, initialize a new Node project in my repo:

npm init -y
npm install @11ty/eleventy luxon

Luxon was for handling dates nicely, since my posts need readable formats.

Then create a .eleventy.js config file to set up directories:

module.exports = function(eleventyConfig) {
  // Passthrough copies for static assets
  eleventyConfig.addPassthroughCopy("src/css");
  eleventyConfig.addPassthroughCopy("src/images");
  // ... other assets

  // Date filters
  eleventyConfig.addFilter("readableDate", dateObj => {
    const { DateTime } = require("luxon");
    return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat("LLLL dd, yyyy");
  });

  // Collections for posts
  eleventyConfig.addCollection("posts", function(collectionApi) {
    return collectionApi.getFilteredByGlob("src/posts/*.md").reverse();
  });

  return {
    dir: {
      input: "src",
      includes: "layouts",
      output: "_site"
    }
  };
};

I moved all content into a src/ folder to keep things organized, posts in src/posts/, layouts in src/layouts/, etc.

Step 2: Convert Layouts and Templates

Jekyll uses Liquid templates in _layouts/ and _includes/. Eleventy defaults to Nunjucks, which I chose for its power.

  • Converted default.html to base.njk with Nunjucks syntax.
  • Made a post.njk for blog posts.
  • Updated the index page to loop over collections.

I kept the structure similar: header, footer, navigation...but added dark mode CSS with variables for colors.

For dark mode, I set up CSS like:

:root {
  --bg-color: #1a1a1a;
  --text-color: #e0e0e0;
}
body {
  background: var(--bg-color);
  color: var(--text-color);
}

Step 3: Migrate Posts and Assets

  • Moved all Markdown posts to src/posts/ and updated frontmatter to use layout: post.njk.
  • Copied images, docs, favicons into src/.
  • Tested locally to ensure everything rendered.

Had to tweak some paths but overall straightforward.

Step 4: Deploy

For deployment, I set up Cloudflare Pages with the build command npx @11ty/eleventy and output to _site. After some config tweaks, it went live without hitches.

Yeah, That’s It, Really

The migration took a weekend, buuuut it was worth it. The site's faster, easier to maintain, and looks sharper in dark mode. If you're on Jekyll and feeling stuck, maybe give Eleventy a shot.