Upgrading an Old Jekyll Project to Jekyll 4: Full Error Diagnosis and Fix
This project was originally built using Jekyll 3.x and worked correctly for several years. Later, the local system Ruby environment was upgraded and Jekyll 4 was installed. This guide documents the complete process of diagnosing and resolving incompatibilities during the migration.
Initial Situation
When the old project was run using:
bundle exec jekyll serve
it immediately started throwing errors and failed to build. The build process halted with dependency resolution failures and version constraint violations.
The goal was to upgrade the existing project in-place, preserving all content and configurations, rather than recreating it from scratch.
Understanding Why Old Jekyll Projects Break
A Jekyll project’s behavior depends critically on Ruby gems defined in:
- Gemfile — Explicitly declared dependencies
- Gemfile.lock — Pinned versions of all transitive dependencies
- theme gemspec — Dependencies of gem-based themes
When Jekyll is upgraded across a major version (3 → 4):
- Old gem versions become incompatible with the new Jekyll API
- Gemfile.lock pins outdated dependencies that conflict with Jekyll 4
- Some gems (notably github-pages) force older Jekyll versions internally
- Configuration keys and plugin APIs may have changed
Therefore, errors are expected unless dependencies are realigned and configuration is reviewed.
Step 1: Inspecting the Project Structure
A thorough analysis of the project revealed:
- A custom theme gem (jekyll-theme-basically-basic.gemspec)
- A Gemfile with multiple plugins including the outdated github-pages
- A _config.yml mixing both
themeandremote_themedeclarations - Outdated version constraints in the Gemfile
This immediately indicated multiple dependency and configuration conflicts that would prevent Jekyll 4 from running.
Step 2: Removing GitHub Pages Constraint
The Gemfile originally contained:
gem "github-pages", group: :jekyll_plugins
The github-pages gem forces Jekyll 3.x internally and manages its own plugin versions.
Action Taken: The github-pages gem was removed completely from the Gemfile.
Reason:
- GitHub Pages infrastructure does not support Jekyll 4 locally
- The github-pages gem intentionally locks Jekyll to 3.x for consistency with GitHub’s rendering
- Keeping this gem makes it impossible to run Jekyll 4 locally
- For local development with Jekyll 4, declare plugins individually instead
Step 3: Resetting Locked Dependencies
The file Gemfile.lock was created under Jekyll 3.x and contained pinned versions of all gems from that era.
Action Taken:
rm Gemfile.lock
Reason:
- Gemfile.lock locks old gem versions that are incompatible with Jekyll 4
- Major version upgrades require Bundler to resolve dependencies fresh
- Without removing the lock file, Bundler will attempt to install Jekyll 3.x dependencies
- This step is mandatory and should be done only once during the upgrade process
Step 4: Understanding the jekyll-remote-theme Error
After deleting Gemfile.lock and running bundle install, Bundler produced this error:
Could not find gem 'jekyll-remote-theme (~> 0.4.3)'
The source contains the following gems matching 'jekyll-remote-theme':
* jekyll-remote-theme-0.4.1
This error indicated that the requested version of jekyll-remote-theme was not available in the gem repository.
Why This Error Occurred
In the Gemfile, the following line existed:
gem "jekyll-remote-theme", "~> 0.4.3"
Bundler interprets the pessimistic version operator ~> 0.4.3 as:
- Allow any version >= 0.4.3
- But strictly < 0.5.0
However:
- Only version 0.4.1 was available in rubygems.org
- 0.4.1 does not satisfy the constraint ~> 0.4.3 (since 0.4.1 < 0.4.3)
- Bundler failed to resolve before installing any gems
The Correct Fix Strategy
At this point, the entire configuration was reviewed:
- The project was already using:
theme: jekyll-theme-basically-basic - This means the theme is loaded as a gem, not fetched remotely
- Having both
themeandremote_themeis a configuration error - jekyll-remote-theme is therefore not required for this setup
Final Decision: Remove jekyll-remote-theme entirely from the Gemfile.
This is the cleanest and most stable solution for Jekyll 4 because:
- It eliminates version constraint conflicts
- It uses the locally installed theme gem for reliability
- It reduces network dependencies
- It improves build reproducibility
Final Corrected Gemfile (Jekyll 4)
source "https://rubygems.org"
gemspec
gem "jekyll", "~> 4.3"
gem "jekyll-feed"
gem "jekyll-paginate"
gem "jekyll-seo-tag"
gem "jekyll-sitemap"
gem "logger"
gem "csv"
Key Changes:
- Removed
github-pagesgem entirely - Updated Jekyll to 4.3.x with flexible versioning
- Declared plugins individually with no version constraints (allowing latest compatible versions)
- Added
loggerandcsvas explicit gems (required by Ruby 3.4+)
Final Corrected _config.yml Theme Section
theme: jekyll-theme-basically-basic
plugins:
- jekyll-feed
- jekyll-seo-tag
- jekyll-sitemap
- jekyll-paginate
Key Changes:
- Declared only
theme:(removed anyremote_theme:entry) - Listed all active plugins under the
plugins:key - Ensured plugin list matches Gemfile declarations
Rebuilding the Project (Correct Order)
After all fixes were applied, the project was rebuilt using the correct sequence:
bundle install
bundle exec jekyll serve
Expected Output:
Configuration file: /path/to/_config.yml
Source: /path/to
Destination: /path/to/_site
Incremental build: disabled. Enable with --incremental
Generating...
Jekyll Feed: Generating feed for posts
done in 2.345 seconds.
Auto-regeneration: enabled for /path/to
Server address: http://127.0.0.1:4000
Server running...
Press ctrl-c to stop.
Jekyll now builds successfully under Jekyll 4, with hot-reload enabled for local development.
Key Lessons for Upgrading Any Jekyll Project
- Never keep github-pages for local Jekyll 4 development — It enforces Jekyll 3.x
- Always delete Gemfile.lock during major upgrades — It prevents dependency resolution
- Do not mix theme and remote_theme — Use one or the other, preferably theme gems
- Ensure Gemfile version constraints match available gems — Use
~>conservatively - Prefer theme gems over remote_theme for stability — Reduces network calls and improves reproducibility
- Test incrementally — Fix one error at a time rather than changing everything at once
- Review _config.yml after upgrade — Configuration keys and plugin behavior may have changed
- Update Ruby if needed — Jekyll 4 benefits from Ruby 2.7+ and runs optimally on Ruby 3.x