Collections and schemas
On this page
A collection is a folder of content files that share a schema, a layout and a URL pattern. Every theme comes with two: pages, every page in content/ outside the other collections, and posts, the dated posts in content/posts/ with a list page at /posts/ and a feed. Themes may add their own, and the config adds more or changes the theme's in kilim.config.ts:
import { defineConfig, z } from "@kilim-dev/core";
export default defineConfig({
theme: "default",
collections: {
talks: {
layout: "post",
permalink: "/talks/:year/:slug/",
list: { title: "Talks", pageSize: 10 },
schema: z.object({
title: z.string(),
date: z.coerce.date(),
description: z.string().optional(),
draft: z.boolean().optional(),
}),
},
},
});| Option | Meaning |
|---|---|
directory | The folder in content/. Defaults to the collection name; "." is all of content/. |
schema | Checks each file's frontmatter. Any Standard Schema works. |
layout | The layout of its pages. A frontmatter layout overrides it. Defaults to page. |
permalink | The URL pattern of its pages; see URLs. |
list | Adds a page listing the entries, newest date first. |
feed | Writes RSS next to the list page. On when the collection has a list. |
fields | Frontmatter fields added to the theme's Zod schema, e.g. { mood: z.string().optional() }. |
Collection folders can be nested: with pages at "." and posts at posts, a file belongs to the deepest collection whose folder holds it. A theme's collection whose folder the site does not have gets no list page. Without a theme there are no collections until the config declares some, and a file outside all of them gets a warning.
z from @kilim-dev/core is Zod. Every file is checked before anything is rendered, and all problems are reported at once, with the file and line:
content/blog/hello.md:3: date: Invalid input: expected date, received Date
content/blog/draft.md:2: title: Invalid input: expected string, received undefinedLayouts and plugins get the validated data, so z.coerce.date() gives them a Date. kilim types writes the collections' types to .kilim/types.d.ts, which types page.data in layouts; kilim dev keeps the file up to date.
Some frontmatter keys mean something to Kilim. Add them to the schema to use them:
| Key | Effect |
|---|---|
title | The page title and the default <title>. |
date | Sorts lists, fills :year, :month and :day in permalinks. |
description | The meta description and link previews. |
image | The Open Graph image instead of the generated one. |
draft | true leaves the page out of the build. |
publishAt | The page appears from this time on. |
expiresAt | The page disappears at this time. |
noindex | Adds noindex and leaves the page out of the sitemap. |
aliases | Old URLs that redirect to the page. |
slug, permalink | Change the URL; see URLs. |
A page is published when it is not a draft, its publishAt has passed and its expiresAt has not. Times are ISO 8601; without an offset they are in the config's timezone (UTC by default). kilim dev shows unpublished pages anyway, with a badge, so you can read them before they go out.
list: true or list: { title, pageSize, permalink, layout } adds a page at the collection's URL, e.g. /blog/, with its entries newest first. With pageSize, later pages are at /blog/page/2/ and so on. A collection with a list also gets a feed at /blog/feed.xml (RSS; Atom and JSON Feed are options of the feed() plugin).