unifying multiple jekyll collections into one search index
Why Use Multiple Collections in Jekyll
Jekyll’s collection feature allows you to manage different types of content with separate configurations and rendering rules. For a knowledge base or documentation site, this is incredibly useful—for example:
- Guides: Step-by-step tutorials or how-to articles.
- References: API or configuration specifications.
- FAQs: Short answers to recurring questions.
- Use Cases: Real-world implementations and examples.
Each collection can live in its own folder and be filtered, styled, or organized independently. But if you want a global search experience using Lunr, you’ll need to merge all collection content into a unified search index.
Understanding the Challenge
Lunr requires one flat JSON structure to create the index. Since Jekyll processes each collection separately, generating a single search.json file with multiple content types requires custom templating.
In this tutorial, we’ll build a shared index from multiple Jekyll collections that includes metadata like collection name, title, and content, making it easier to filter or highlight specific content types in the search results.
Configuring Multiple Collections in Jekyll
First, define your collections in _config.yml:
collections:
guides:
output: true
references:
output: true
faqs:
output: true
usecases:
output: true
Each of these will be stored in folders prefixed with an underscore (e.g., _guides, _references), and Jekyll will treat them as individual collections.
Generating a Unified search.json
Create or modify your search.json to include entries from all collections:
---
layout: none
---
[
{% assign all_docs = site.guides | concat: site.references | concat: site.faqs | concat: site.usecases %}
{% for doc in all_docs %}
{
"title": "{{ doc.title | escape }}",
"url": "{{ doc.url | relative_url }}",
"collection": "{{ doc.collection }}",
"content": {{ doc.content | strip_html | strip_newlines | jsonify }}
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
This will create a single JSON array that merges content from all defined collections.
Modifying Lunr Initialization
Now, update your JavaScript search logic to recognize and display the collection type:
let idx = null;
let documents = [];
fetch("/search.json")
.then(res => res.json())
.then(data => {
documents = data;
idx = lunr(function () {
this.ref("url");
this.field("title");
this.field("content");
this.field("collection");
data.forEach(function (doc) {
this.add(doc);
}, this);
});
});
document.getElementById("search-input").addEventListener("input", function () {
const query = this.value;
const results = idx.search(query);
const output = document.getElementById("search-results");
output.innerHTML = "";
results.forEach(result => {
const match = documents.find(doc => doc.url === result.ref);
const item = document.createElement("li");
item.innerHTML = `${match.title} (${match.collection})`;
output.appendChild(item);
});
});
This approach adds a visual cue about which collection the result belongs to, improving user orientation in mixed-content environments.
Benefits of a Unified Search Index
- One Search, All Content: Users don’t have to choose a section to search in.
- Consistent UX: Results across different collections appear in a uniform layout.
- Filter Ready: The collection field can be used for post-search filtering.
Bonus: Filtering Results by Collection
Want users to filter search results by category or collection?
const selectedCollection = document.getElementById("filter").value;
const filteredResults = results.filter(result => {
const match = documents.find(doc => doc.url === result.ref);
return match.collection === selectedCollection || selectedCollection === "all";
});
Add a dropdown in your HTML:
<select id="filter">
<option value="all">All</option>
<option value="guides">Guides</option>
<option value="references">References</option>
<option value="faqs">FAQs</option>
<option value="usecases">Use Cases</option>
</select>
Then apply the filter after a search query is executed.
SEO and Accessibility Considerations
Make sure all your content is still accessible via normal navigation for bots and users who prefer not to use search. Collections should be linked through menus or breadcrumbs. Also, ensure that your search input and results are keyboard accessible and labeled properly for screen readers.
Scalability Tips
- Break large indexes into separate files if content grows beyond a few hundred documents.
- Use collection-specific JSON files and combine them with JavaScript at runtime if needed.
- Keep the content field concise by limiting it to the excerpt or summary.
Conclusion
By unifying multiple Jekyll collections into one search index, you create a seamless experience that matches modern user expectations. Whether you're building a developer portal, product documentation, or internal knowledge base, a unified search makes the site faster to navigate and easier to maintain.
In the next article, we’ll explore how to build multilingual search indexes for collections written in different languages—enabling your site to truly go global.