Data
Three options for sourcing structured data in zfb — content collections, frontmatter-only entries, and plain TS modules.
zfb gives you three different routes for getting structured data into a page, and the right choice depends on the shape of the data and how much ceremony you want around it.
1. Content collections
When the data is prose — blog posts, docs articles, recipes — use a content collection. Each entry is a Markdown file with frontmatter, the frontmatter is validated against a schema, and the body is rendered to HTML for you. See Content Collections for the full story.
This is the right choice whenever the body of each entry is meant to be read.
2. Structured records via frontmatter-only entries
When the data is structured — a list of products, a directory of team members, a set of pricing tiers — you can use a content collection whose entries carry all their data in frontmatter with an empty body. The collection walker accepts .md and .mdx files; a file with just a frontmatter block and no body is perfectly valid:
---
name: "Widget Pro"
price: 49
featured: true
---Declare the directory in zfb.config.ts with an optional schema for per-field validation (see defineConfig):
export default {
collections: [
{
name: "products",
path: "data/products",
schema: {
type: "object",
properties: {
name: { type: "string" },
price: { type: "number" },
featured: { type: "boolean" },
},
required: ["name", "price"],
},
},
],
};Load entries the same way as content entries — entry.data holds the validated frontmatter; entry.Content renders the (empty) body and can be ignored:
import { getCollection } from "zfb/content";
const products = getCollection("products");This approach earns its keep when you want per-entry schema validation, slug derivation, and the same getCollection API as your prose content — without requiring a Markdown body.
JSON / YAML / TOML data files not yet supported
The collection walker currently accepts only .md, .mdx, and .tsxfiles. JSON, YAML, and TOML data files are skipped with a build warning (zero entries returned). For raw structured data without a Markdown wrapper, use a plain TS module (option 3 below) until data-file collection support ships.
3. Plain TS modules under data/
For everything else — small lookups, helper functions, derived constants — a regular TypeScript module is the lightest path:
// data/site.ts
export const siteName = "My Site";
export function formatDate(date: Date) {
return date.toISOString().slice(0, 10);
}Import it from any page or component:
import { siteName, formatDate } from "../data/site";There is no schema, no slug, and no per-entry overhead. Use this when the "collection" framing would be more ceremony than the data deserves.
Picking the right tool
A useful rule of thumb:
The data is content meant to be read → content collection.
The data is structured records that share a shape and benefit from per-entry validation → frontmatter-only
.mdentries in a collection.The data is a handful of constants or a helper → TS module under
data/.
You can mix all three in the same project without conflict.