Goodbye Jekyll, Hello Eleventy.
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.htmltobase.njkwith Nunjucks syntax. - Made a
post.njkfor 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 uselayout: 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.