Building a Technical Blog with Jekyll and GitHub Pages
I wanted a simple place to publish technical experience reports without having to manage any infrastructure. GitHub Pages + Jekyll quickly became the obvious choice: free, versioned, and automatically deployed on every push.
This blog was built in collaboration with Claude Code, Anthropic’s CLI. From project initialization to debugging the language switcher, Claude Code acted as the technical counterpart throughout the session — a good example of what can be achieved through pair programming with an AI assistant. Here are the main steps.
Initialization
The starting point is a standard GitHub repository. Jekyll generates a static website from Markdown files. The minimal structure looks like this:
_posts/ ← articles
assets/ ← images, CSS
_config.yml ← site configuration
Gemfile ← Ruby dependencies
index.md ← homepage
The _config.yml file defines the essentials: title, URL, theme, and plugins.
Choosing a theme: Minimal Mistakes
The default theme (Minima) is functional but quite minimal. I chose Minimal Mistakes, a very complete theme offering multiple color schemes. It integrates via remote_theme, meaning there is no need to fork the repository:
remote_theme: mmistakes/minimal-mistakes
minimal_mistakes_skin: "air"
The air skin provides a clean and readable layout.
Tags and navigation
Minimal Mistakes natively supports tags through a dedicated layout. You simply create a _pages/tags.md page with layout: tags, declare the archive in _config.yml, and configure navigation in _data/navigation.yml:
tag_archive:
type: liquid
path: /tags/
Footer customization
Minimal Mistakes provides hooks to customize the footer. I overrode _includes/footer.html to add links to my social networks (LinkedIn, X, GitHub) using Font Awesome icons, along with an RSS link.
One important detail: Minimal Mistakes loads footer/custom.html before footer.html. If both are populated, icons appear twice. You must choose one or the other.
Multilingual support with jekyll-polyglot
This was the most ambitious part. jekyll-polyglot allows generating multiple language versions of a site from a single source. Configuration in _config.yml:
languages: ["fr", "en"]
default_lang: "fr"
exclude_from_localization: ["assets"]
parallel_localization: false
Posts are organized into language-specific subfolders:
_posts/
fr/ ← French articles
en/ ← English articles
Each article includes a lang: fr or lang: en attribute in its front matter.
GitHub Actions required
jekyll-polyglot is not included in the list of plugins allowed by GitHub Pages. Therefore, the site must be built manually using GitHub Actions and deployed as an artifact.
In the repository settings, the GitHub Pages source must be set to “GitHub Actions” (not “Deploy from a branch”).
The workflow .github/workflows/jekyll.yml installs gems, builds the site with Jekyll, and deploys using actions/deploy-pages.
Interface translations
Minimal Mistakes uses site.locale for interface strings (reading time, dates, etc.). With polyglot, some includes must be overridden to use page.locale instead — especially page__meta.html and page__date.html.
Dates also need to be formatted using Liquid filters to avoid dependency on the system locale.
For the homepage, _layouts/home.html also requires filtering to display only posts from the active language:
{% assign posts = site.posts | where: "lang", site.active_lang %}
The language switcher: an unexpected challenge
Adding a simple “FR / EN” link to every page sounds easy. In practice, polyglot introduces two complications:
-
URL post-processing: polyglot scans the final HTML output of the EN build and automatically adds
/en/to all relative links. Any Liquid-generated URL pointing to the FR version gets rewritten to EN. -
jekyll-include-cache: Minimal Mistakes caches includes using
{% include_cached %}. If the masthead usespage.url, the first cached value is reused for every page — meaning the language link always points to the first rendered article.
The solution in both cases: JavaScript. By reading window.location.href at runtime in the browser, we bypass both polyglot’s post-processing and include caching:
// FR → EN: insert /en/ after baseurl
document.getElementById('masthead-en-link').href =
window.location.href.replace('/posts/', '/posts/en/');
// EN → FR: remove /en/
document.getElementById('masthead-fr-link').href =
window.location.href.replace('/en/', '/');
Conclusion
Jekyll + GitHub Pages remains an excellent combination for a simple technical blog. Adding multilingual support with jekyll-polyglot is powerful but requires a few adjustments, especially around include caching and URL post-processing. Once these pitfalls are understood, the result is clean and fully static.