Jekyll Content Modeling: Choosing Between Pages, Data Files, and Collections
A decision guide for Jekyll content architecture comparing static pages, YAML data files, and collections, with trade-offs and implementation checks.
23 Dec 2025, 01:59 UTC

The decision and its constraints
When you need to manage structured content in Jekyll—a staff directory, pricing tiers, or a navigation menu—the first question is not just where to store the data, but whether each item needs its own URL. The practical takeaway: use static pages when items are destinations, data files when they are template inputs, and collections when you need both structure and individual addresses.
Choosing between static pages, data files, and collections depends on three constraints. First, does each item require a unique permalink? Second, how much per-item layout customization do you need? Third, how large will the dataset grow? Pages and collections generate URLs automatically and support front matter, making them suitable for content that users visit directly. Data files are pure data structures injected into templates, ideal for lists and configuration-like content that does not need its own address.
Comparing supported options
| Option | Individual URLs | Front matter per item | Build behavior | Best for |
|---|---|---|---|---|
| Static pages (posts/pages) | Yes | Yes | Rendered per file | Blog posts, documentation pages |
Data files (/_data/) |
No | No | Parsed into memory once | Navigation, team lists, config-like data |
| Collections | Yes | Yes | Rendered per document | Hybrid content: events, products, authors |
Static pages include posts in _posts and any Markdown or HTML files with front matter. They are the default choice when content is chronological or hierarchical and each item is a destination. Data files live in _data and are written in YAML, JSON, or CSV. They are read into the site.data namespace and accessed through Liquid loops. Collections are custom document sets defined in _config.yml that behave like pages but with arbitrary grouping. Like data files, collection documents can be iterated over in Liquid, but they also generate individual output files when output is enabled.
Trade-offs that matter
Build-time behavior
Data files are parsed entirely into memory during the build. For small-to-medium datasets this is efficient, but as the file grows, Jekyll must parse every entry on each build, which can increase build time significantly. Pages and collections are rendered individually, which avoids a single large parse but adds per-file overhead. If your dataset is small and stable, a data file is usually faster to iterate on than hundreds of individual files.
URL generation
Static pages and collections generate URLs automatically based on their location and front matter. Data files have no built-in permalink support. To expose a data item at its own address, you must iterate over it in a page template and construct the path manually using Liquid. This adds template complexity and makes the URL structure implicit rather than declarative.
Layout flexibility
Front matter on pages and collection documents lets you select different layouts per item. For example, one collection document can use a layout called wide while another uses sidebar. Data files rely entirely on the parent template's logic, so conditional rendering must happen inside the Liquid loop rather than in metadata. This keeps data files simple but pushes presentation logic into the template.
Concrete implementation
Injecting a data file into a template
Create a YAML file in the _data directory, for example _data/team.yml:
- name: Alex Rivera
role: Infrastructure
bio: Maintains build pipelines.
- name: Sam Chen
role: Documentation
bio: Writes API guides.
Reference the file in a template, such as team.html, using the site.data namespace:
{% for member in site.data.team %}
<article>
<h3>{{ member.name }}</h3>
<p>{{ member.role }}</p>
<p>{{ member.bio }}</p>
</article>
{% endfor %}
Each key in the YAML list becomes a property of the member variable inside the loop.
Registering a collection for individual URLs
Collections must be declared in _config.yml before Jekyll recognizes them. Add a collection definition with output enabled:
collections:
projects:
output: true
permalink: /projects/:path/
Then create documents in the matching directory, for example _projects/alpha.md:
---
layout: project
title: Alpha Initiative
---
Detailed project description goes here.
With output: true, Jekyll renders each document to its own page. Without it, the collection exists in memory but generates no HTML files.
Validating the build
From your project root, run the build command. If you use Bundler, prefix it with bundle exec:
bundle exec jekyll build
After the build completes, inspect the _site directory. For the data file example, open _site/team.html and confirm that the member names and roles appear in the rendered HTML. For the collection example, verify that _site/projects/alpha/index.html exists and contains the front matter title. If collection pages are missing, check that the directory name matches the collection key exactly and that output is set to true.
Limitations and when to reconsider
Data files scale poorly beyond thousands of entries because the entire file is parsed into memory on every build. If your list grows large or changes frequently, a collection or individual pages may be more maintainable despite the file-count overhead. Collections add configuration complexity and require explicit registration; if you only need a simple list without URLs, the extra _config.yml entry is unnecessary. The behavior described here reflects Jekyll 4.x conventions, where directory naming and Liquid scoping are stable. Verify your installed version with jekyll --version before relying on specific defaults.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.