The long road to a unified docs platform

When GitHub set out to replace its two aging documentation sites with the current docs.github.com, the engineering challenge was as much about content strategy as it was about code. The company had been running separate sites for end-user help and developer documentation, each with its own codebase and conventions. Unifying them meant rethinking how documentation was organized, versioned, and generated.

The goals were practical: better reading and navigation for users, and better publishing tools for writers. Achieving them required moving away from static site generation towards a dynamic backend, then combining years of content from two different sources.

Why static sites stopped working

Both docs sites were originally built on Jekyll, with Markdown files in a content directory and YAML data in a data directory. That setup served GitHub well for years, but the constraints of static builds eventually became a liability, particularly with versioned documentation for GitHub Enterprise Server.

GitHub ships a new Enterprise Server release every three months and maintains docs for each version for a year. At any given time, documentation for four different server versions is live on the site. To handle this, the docs team relied on single-sourcing: each article could contain conditional Liquid templating to render version-specific content, like so:

{% if page.version == 'dotcom' or page.version ver_gt '2.20' %}

Content relevant to new versions

{% else %}

Content relevant to old versions

{% endif %}

But static site generators build once. They don't produce multiple versions of a page. So the team relied on a backport process: writers would manually build Enterprise Server content separately from GitHub.com docs, requiring review, staging deploys, and separate publishing pipelines. As Enterprise Server releases accumulated, backports grew slower and more error-prone, often getting forgotten entirely.

First step: a dynamic backend

The team chose to keep its Markdown and YAML writing conventions—they worked well and writers didn't need to learn new paradigms—but replaced the build process with a Node.js service running Express. The new site, launched in February 2019, loads metadata for all pages at server startup and renders content dynamically at page load.

The rewrite brought immediate improvements:

  • Deploys went from ~10 minutes to near-instant. There was no need to rebuild the entire site for each change.
  • Backports were eliminated. Enterprise Server content loaded alongside GitHub.com docs, using the same dynamic version rendering.
  • Fastly CDN was added as a global edge cache to keep page loads fast despite the move away from static files.
  • Search was upgraded to Algolia.
  • Deployments became fully automated through GitHub flow, with staging and production updates handled automatically rather than through chatops.

This dynamic foundation also made internationalization possible. Japanese and simplified Chinese versions launched in June 2019, with Spanish and Portuguese following later that year.

Restructuring for multiple products

Once help.github.com was on the new stack, developer.github.com remained on the old static build, and parts were breaking down. But bringing that content into the unified codebase first required a more robust way to organize products.

The old help site did have a product chooser on its homepage, but behind it, content was organized inconsistently. The content/dotcom/articles directory alone held nearly a thousand Markdown files with no hierarchy, and URLs like help.github.com/articles/<article> gave no indication of which product they belonged to.

The replacement was a consistent, product-centric file structure: content/<product>/<category>/<article>, matched by URL paths. The team built a new table-of-contents system, refactored product handling on the backend, and added redirects from legacy article URLs to the new scheme. GitHub Actions was the first new product released on this structure in 2019.

Making API docs maintainable

The real payoff of the new backend came with API documentation, which had been the source of the developer site's most difficult maintenance problems.

REST docs from an OpenAPI schema

GitHub's REST docs had been handwritten for a decade. Updating input and response parameters manually was time-consuming, and versioning those updates across GitHub.com and Enterprise Server was nearly unmanageable. Readers had long requested standardized features like code samples, but the handwritten format made them impractical to provide.

The path forward came from an existing community effort: Octokit maintainer Gregor Martynus had started generating an OpenAPI schema describing GitHub's API. Rather than starting from scratch, GitHub invested in that work and partnered with Redoc.ly, a firm specializing in OpenAPI schema design, to get the schema production-ready. A new pipeline consumes the OpenAPI schema and renders the REST docs at docs.github.com/rest/reference.

Self-publishing GraphQL docs

GraphQL documentation was a different problem. Since the GraphQL API launched in 2017, GitHub had autogenerated its docs from a schema using gjtorikian's graphql-docs tool. That pipeline worked, but it was written in Ruby and didn't fit the new Node.js backend.

Instead of settling for an existing JavaScript generator that didn't fit the requirements, the team wrote its own script. The script takes a GraphQL schema, sanitizes it, and outputs JSON files containing only the data needed for rendering. HTML files loop over the JSON and render it on page load, and the whole pipeline runs on a scheduled GitHub Actions workflow that automatically opens and merges pull requests when the schema changes.

The result: writers never touch GraphQL documentation because it publishes itself.

Migrating content programmatically

With API docs handled, the remaining developer site content—docs for GitHub and OAuth apps, GitHub Marketplace, and webhooks—was mostly vanilla Markdown. Migration scripts imported files, processed them, and ran automated tests.

The content strategist built a spreadsheet mapping every piece of old developer content to its new product-based location, complete with titles and intros. The team ran the migration scripts repeatedly, reviewing changes between each pass before finalizing the move. The finish line was a single, unified site at docs.github.com.

For a documentation site, a 404 is a hard stop to a reader's momentum. GitHub's docs team treats redirects as a core requirement, not an afterthought, and maintains more than 20,000 of them in the codebase to support renamed or relocated files.

Some of those redirects require careful logic. A URL containing enterprise, for instance, isn't necessarily a real Enterprise Server path. When someone visits https://docs.github.com/enterprise without a version number, the site injects the latest version into the URL — but only when the path genuinely indicates an Enterprise Server page. Similarly, every URL without a language code gets redirected to the /en prefix, and links on localized pages are rewritten so that a reader on a Japanese page is taken to the /ja version of the target article rather than the /en one.

Upcoming blanket redirects will map most https://developer.github.com links to https://docs.github.com. Those blanket rules are straightforward; the harder work was migrating the developer content itself, which changed names and locations across the board. Paths like /v3 became /rest/reference, and /apps became /developers/apps. To catch every dead link, the team worked through a list of the top few hundred developer.github.com URLs pulled from Google Analytics, fixing redirects path by path.

With this redirect infrastructure in place, users following legacy bookmarks, outdated links, or federation content can still land on the page they were looking for.

Building on the foundation

The hard part now is behind them: docs.github.com has the infrastructure to support continuous improvement of the content experience. More engineering write-ups on the platform are planned.