The pages gem pins Ruby and its dependencies so your local build matches the server
A simple Ruby Gem to bootstrap dependencies for setting up and maintaining a local Jekyll environment in sync with GitHub Pages
At a glance
- What is it?
- A Ruby gem whose purpose is version agreement rather than features: it pins Ruby, Jekyll, Kramdown, Liquid and the rest to what GitHub Pages runs, and ships CLI tools to list those versions and check DNS. Suited to previewing a Pages site locally, and pointless outside that context.
- Who is it for?
- Adopt the pages gem if you build a GitHub Pages site and have been burned by a local build that succeeded while the published site differed, since version agreement is exactly the problem it solves. Do not adopt it as a general Jekyll setup tool, because the versions it pins are the ones GitHub Pages runs and nothing else.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 43 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The stated goal is parity with the server, not convenience
The gem describes itself as a bootstrap for a local Jekyll environment in sync with GitHub Pages, and the project goals section is more precise than that. The goal is to bootstrap and maintain a Jekyll build environment that most closely matches the GitHub Pages build environment, and the mechanism is explicit requirements shared between users' computers and the build servers, so that a local build is consistently also the result of the server's build.
That is a narrow goal and worth being clear about, because it explains everything else. The project states that additional tools which integrate with the GitHub API to make managing Pages sites easier are not the primary goal, though they may be within scope. The gem is not a site management tool. It is a version lock.
The homepage is pages.github.com, and the licence is MIT.
Ruby itself is versioned, which is the part people forget
The section titled what is versioned names two things, and the first surprises people.
The first is Ruby itself, the version with which Jekyll is executed. The reasoning given is that although Jekyll itself may be compatible with prior or future Ruby versions, different execution environments yield different results, with the example that Ruby 1.8.7 parses YAML differently than 1.9.3, and that Kramdown has trouble processing mailto links prior to 1.9.3. The gem therefore versions Ruby alongside the gems, and says it does so despite no known incompatibilities.
That is the honest position: the pin is not there to fix a bug you can point at, it is there so that the class of difference cannot appear.
The second is the dependencies, which includes Markdown processors and any other Jekyll dependency where version incongruency may produce unexpected results. The traditional examples given are Maruku, Kramdown, RedCloth, liquid, rdiscount and redcarpet, described as strictly maintained due to known breaking changes. Markdown is where local and remote builds historically diverge most often.
The conventional install is two steps and a Bundler warning
There are two routes in the README, and the first one starts with a constraint: make sure you have Bundler greater than v1.14 by running gem update bundler before the next steps. That instruction is the first thing in the flow, which tells you the assumed starting point is an old Ruby setup.
After that, one line in the Gemfile:
gem 'github-pages', group: :jekyll_pluginsand then bundle install.
The note that follows is the part that saves time. You are not required to install Jekyll separately: once the github-pages gem is installed you build with jekyll build and preview with jekyll serve. The dependency arrives through the gem rather than as a separate install step.
Updating is symmetric: gem update github-pages if you installed it directly, or bundle update github-pages under Bundler.
The Docker route fixes the Ruby problem by not using your Ruby
The containerised alternative exists to avoid installing tools into your environment, and the Dockerfile shows how thoroughly it does that. The base image is ruby with an ARG defaulting to Ruby 3.3, and it installs git, locales, make and nodejs on top.
The interesting part is the bundler wiring. Only .git, the Gemfiles, the gemspec, lib/ and bin/ are copied first, bundle config local.github-pages points bundler at that partial tree, and bundle install runs with NOKOGIRI_USE_SYSTEM_LIBRARIES=true. The rest of the repository is copied afterwards, so dependency installation does not invalidate on every source change.
Environment is pinned too: LANG, LANGUAGE and LC_ALL are all set to en_US.UTF-8, and BUNDLE_GEMFILE points at the container's Gemfile. The working directory is /src/site and the default command is jekyll serve bound to 0.0.0.0 on port 4000.
There is also a Dockerfile.alpine for a smaller image, built by make image_alpine.
Four ways to start a server, and a shell function that hides two of them
The Makefile builds the image as gh-pages and offers four entry points. From the repository root, make image and make image_alpine. For serving, SITE=PATH_TO_YOUR_PROJECT make server, or the raw docker run from any directory:
SITE=PATH_TO_YOUR_PROJECT docker run --rm -p 4000:4000 -v `realpath ${SITE}`:/src/site gh-pagesThe Makefile server target fails early with a message telling you to specify SITE if the variable is unset, which saves a confusing docker error later. It also runs the container as your own uid and gid, so files written into the mounted site directory belong to you.
Two further options come from contrib/func.sh. Sourcing that file defines a github-pages shell function, once added to your shell startup file:
source $PATH_TO_THIS_DIRECTORY/contrib/func.shWith that sourced, github-pages runs against the current Jekyll site, and github-pages $PATH $PORT targets a specific site and port. The README notes the argument order assumes you are more likely to want a custom path than a custom port, and that this approach exists as a friendlier alternative to make server or docker run. Both serve on port 4000 by default.
Two CLI tools, and a flag that changes what you are testing
The github-pages command carries more than a launcher. versions prints the pinned gems and their versions as a table:
$ bundle exec github-pages versions
+---------------------------+---------+
| Gem | Version |
+---------------------------+---------+
| jekyll | x.x.x |
| kramdown | x.x.x |
| liquid | x.x.x |The --gemfile flag emits the same dependency list in valid Gemfile format, which is what you want when you are pinning versions deliberately rather than just inspecting them. The live server side of the same list is published at pages.github.com/versions, so you can compare your local output against production.
health-check checks your Pages site for common DNS configuration problems, and the sample output shows what a failure looks like:
$ github-pages health-check
Checking domain foo.invalid...
Uh oh. Looks like something's fishy: A record points to deprecated IP addressThe third tool is a flag rather than a command. DISABLE_WHITELIST=true in front of jekyll build or jekyll serve lets you run a plugin that is not whitelisted for use on GitHub Pages. The README is explicit that this only applies when previewing locally, so it is a development aid and not a way to ship an unwhitelisted plugin.
Maintenance state and what to check before adopting
The published releases are v230 on 2024-02-13, v231 on 2024-02-15 and v232 on 2024-08-06, with the last push on 2026-09-10. So commits continue while the tagged releases are from 2024. For a gem whose entire job is to be the server's version list, that gap is the thing to check: the releases are what GitHub Pages ships, and the default branch may be ahead of them.
The release process itself is documented for maintainers. Running script/release from master creates and tags the release, and then opens pull requests in other repositories, which the releaser is responsible for updating and deploying. The repositories named are github-pages, jekyll-build-pages and pages.github.com. That chain is a useful reminder that the versions you install originate from a coordinated process rather than from this repository alone.
The repository layout matches a conventional gem: github-pages.gemspec, lib/, bin/, spec/ with an .rspec file, a .rubocop.yml, a .ruby-version, a Gemfile, the two Dockerfiles, a .dockerignore, contrib/, docs/ and script/.
MIT licensing means no obligation beyond attribution and notice when you redistribute.
Editorial conclusion
Adopt the pages gem if you build a GitHub Pages site and have been burned by a local build that succeeded while the published site differed, since version agreement is exactly the problem it solves. Do not adopt it as a general Jekyll setup tool, because the versions it pins are the ones GitHub Pages runs and nothing else. Verify first the Ruby version you are on, because the gem versions Ruby itself as well as the gems, and check pages.github.com/versions against the output of bundle exec github-pages versions before debugging a build difference.
Frequently asked questions
What does the github-pages gem do?
It bootstraps a local Jekyll environment whose versions match the GitHub Pages build environment, relying on explicit requirements shared between user machines and the build servers so a local build matches the server build.
How do I install the github-pages gem?
Update Bundler first with gem update bundler, then add gem 'github-pages', group: :jekyll_plugins to your Gemfile and run bundle install. You do not need to install Jekyll separately.
How do I run a Jekyll site in a container with the github-pages gem?
Run make image from the repository root to build an image tagged gh-pages, or make image_alpine for the smaller alpine variant, then start it with SITE=PATH_TO_YOUR_PROJECT make server or the equivalent docker run command mapping port 4000 and mounting the site at /src/site.
How do I see which dependency versions the gem pins?
Run bundle exec github-pages versions for a table of gems and versions, adding --gemfile to emit the list in Gemfile format. The live server side of the list is published at pages.github.com/versions.
Can I use a Jekyll plugin that GitHub Pages does not allow?
Locally, yes, by prefixing the command with DISABLE_WHITELIST=true, for example DISABLE_WHITELIST=true jekyll serve. The README states this option is only available when previewing the site locally.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/github-pages-gem)Was this useful?