implement versioned documentation with dynamic sidebars in Jekyll

Why versioned documentation is essential for growing projects

As your product or API evolves, documentation needs to reflect the current and past states accurately. Users running an older version shouldn't be confused by instructions or options that don't apply to them. A versioned documentation system allows each major release to have its own isolated content and sidebar structure.

This ensures consistency, reduces support overhead, and gives users confidence that they're reading the right instructions for their setup.

Step 1: Set up version-specific collections

The cleanest way to implement versioned docs in Jekyll is to use separate collections per version:


_config.yml

collections:
  v1:
    output: true
    permalink: /v1/:path/
  v2:
    output: true
    permalink: /v2/:path/

Then in your repo:


_v1/
  getting-started.md
  auth.md

_v2/
  getting-started.md
  auth.md
  webhooks.md

Each version gets its own directory, navigation, and Markdown files.

Step 2: Add version and order metadata in front matter


---
title: "Authentication"
version: "v2"
order: 2
---

This helps in sorting sidebars and maintaining clean routing.

Step 3: Create YAML files for sidebar structure per version

In _data/ folder, define sidebars per version:


_data/sidebars/
  v1.yml
  v2.yml

# _data/sidebars/v2.yml
- title: "Getting Started"
  url: "/v2/getting-started/"
- title: "Authentication"
  url: "/v2/auth/"
- title: "Webhooks"
  url: "/v2/webhooks/"

Step 4: Create a layout include that renders the dynamic sidebar


{% raw %}
{% assign current_version = page.version %}
{% assign nav = site.data.sidebars[current_version] %}

<nav class="sidebar">
  <ul>
    {% for item in nav %}
      <li>
        <a href="{{ item.url }}" class="{% if page.url == item.url %}active{% endif %}">{{ item.title }}</a>
      </li>
    {% endfor %}
  </ul>
</nav>
{% endraw %}

This logic dynamically loads the correct sidebar YAML based on the current page’s version.

Step 5: Link between versions (version switcher)

Allow users to switch documentation versions using a dropdown or links.


{% raw %}
<div class="version-switcher">
  <label for="version">Version:</label>
  <select onchange="location = this.value;">
    <option value="/v1{{ page.url | remove_first: '/v2' }}">v1</option>
    <option value="/v2{{ page.url | remove_first: '/v1' }}" selected>v2</option>
  </select>
</div>
{% endraw %}

You can refine this logic with JavaScript or Jekyll filters to better match path patterns.

Step 6: Handle shared assets between versions

To avoid duplication, create a shared folder like _includes/versioned/ or use default layouts with {% include_relative %} logic.

Step 7: Create a landing page for each version

At /v1/index.md and /v2/index.md, add intro content or changelog highlights for that release.


---
layout: default
title: "Version 2.0 Documentation"
permalink: /v2/
---

Bonus: Auto-highlight latest version on homepage


{% raw %}
{% assign latest_version = "v2" %}
<p>You're reading version: {{ latest_version }}. <a href="/{{ latest_version }}/">Read latest docs →</a></p>
{% endraw %}

You can even store the latest version name in _data/site.yml for maintainability.

Best practices for versioned docs in Jekyll

  • Use Git branches or collections—not folders inside _posts
  • Use Liquid and YAML to keep structure DRY
  • Link clearly between versions, and show update logs
  • Encourage contributors to follow version structure in PRs

Conclusion: Scalable versioning keeps your docs future-ready

Static sites like Jekyll can absolutely support advanced use cases like versioned documentation—as long as you design the structure early. By isolating each version into collections and driving navigation with YAML, you get maximum flexibility with minimum repetition.

Combined with dynamic sidebars and Liquid logic, you offer a seamless experience to users—whether they're reading version 1.0 from two years ago or testing bleeding-edge beta features in 3.0.