version control for jekyll docs with yaml and collections
Managing Documentation Versions Without Complexity
As your project matures, the documentation needs to grow along with it. But simply appending new content to existing pages creates confusion. Users looking for version-specific instructions may end up applying outdated guidance or miss new features. That’s why scalable documentation demands structured version control—from content structure to navigation to deployment.
The Pitfall of Single-Version Docs
For early-stage projects, one set of docs is often enough. But this breaks down when:
- Your API introduces breaking changes
- Installation instructions vary by platform
- Feature sets evolve across releases
Maintaining a single source of truth for each version of your project ensures clarity and trust in your documentation.
Jekyll Collections as a Foundation for Versioning
The easiest way to implement versioned documentation in Jekyll is through collections. Each version lives in its own subdirectory, controlled by a dedicated collection definition in your _config.yml.
Configuration Example
collections:
docs_v1:
output: true
permalink: /v1/docs/:path/
docs_v2:
output: true
permalink: /v2/docs/:path/
This setup lets you organize content like this:
_docs_v1/
getting-started.md
api.md
_docs_v2/
getting-started.md
api.md
Jekyll compiles each collection to its defined path. You can maintain full control over which versions are visible and where.
Switching Between Versions
Each version should include a dropdown or toggle to help users switch context. Store the list of versions in a YAML file for reuse across layouts:
versions:
- id: v2
label: Version 2 (latest)
url_prefix: /v2/docs/
- id: v1
label: Version 1
url_prefix: /v1/docs/
Use this data to populate a version switcher:
{% raw %}
{% endraw %}
This simple UI element goes a long way in guiding your users through the correct documentation path.
Integrating Data-Driven Navigation Per Version
As with base navigation, version-specific menus should live in _data for maintainability. Organize your navigation data by version:
_data/
nav/
v1.yml
v2.yml
Example structure:
v2.yml:
- title: Getting Started
url: /v2/docs/getting-started/
- title: API Reference
url: /v2/docs/api/
Then load the correct file dynamically based on page context:
{% raw %}
{% assign version_id = page.collection | remove: "docs_" %}
{% assign nav = site.data.nav[version_id] %}
{% for item in nav %}
- {{ item.title }}
{% endfor %}
{% endraw %}
Advantages of This Approach
- Easy to add new versions with minimal duplication
- Navigation stays consistent and manageable
- Data files can be localized or reused across templates
Practical Case: Scaling to Multiple Product Versions
Let’s revisit the case of a hardware maker publishing documentation for multiple board models. Each board model (and its firmware) has slightly different specs and commands. Instead of scattering differences in footnotes, the team splits each version into its own collection.
How the Team Implemented It
- Content folders:
_docs_boardA,_docs_boardB - Navigation files:
boardA.yml,boardB.yml - UI toggle: Select menu above the sidebar
- Search: Index generated per collection using Pagefind
Users could switch between versions without losing their place. Contributors didn’t have to dig through if-else logic in templates. And the team could sunset outdated versions by simply removing their collections.
Maintaining Clean URLs and Canonical Structure
With versioning comes the risk of cluttered or duplicate URLs. Use clear permalinks and canonical tags to help search engines understand your structure.
Setting Canonical Tags
In your layout file:
{% raw %}
{% endraw %}
Redirecting Deprecated Pages
If you phase out a version, use Jekyll’s jekyll-redirect-from plugin to send traffic to the latest equivalent page.
redirect_from:
- /v1/docs/old-page/
redirect_to: /v2/docs/new-page/
This ensures users and bots don’t end up on 404s when older versions are retired.
Tips for Keeping Versioned Docs Healthy
Audit for Drift
Use CI tools to check whether key docs across versions are diverging unnecessarily. Aim to reuse content where possible and isolate only what’s version-specific.
Document the Structure Itself
Write internal documentation explaining how collections and navigation files work. It’s easy to forget these conventions months later, especially for new contributors.
Label Versions Clearly
On every page, display the version prominently—ideally in both the header and footer—to avoid confusion for users skimming via search engines.
Conclusion
Scalable documentation means thinking ahead. With Jekyll collections and data-driven navigation, managing multiple versions of your content doesn’t have to be a headache. Whether you’re publishing for APIs, developer tools, or hardware products, this approach offers clarity for users and control for maintainers.
Checklist Before You Scale
- Create distinct collections for each major version
- Build navigations dynamically using YAML files
- Add version switchers to your layout
- Validate for broken links across versions
- Establish internal documentation for your content model
When done right, your docs become a stable, trustworthy resource that scales with your product—not against it.
