Collections are lattice's typed content groups. Each collection says two things:
- where to find a set of Markdown files
- which frontmatter fields every file in that set must satisfy
That is the main structural guarantee in the build: a page is not just "some Markdown in a folder." It belongs to a named collection with a declared schema.
Collections live in a separate config file. In this repo, the example is example/collections.cfg:
[posts]
schema = title:String, date:String, tags:Optional[Array[String]], draft:Optional[Bool]
dir = example/content/posts
[projects]
schema = title:String, status:String, description:Optional[String]
dir = example/content/projects
[data.nav]
required = title,subtitle,cta
[data.site]
required = owner,footerThe current parser supports two section kinds:
[collection_name]for content collections[data.file_name]for required keys in template data files
Each collection currently supports these keys:
schema: a comma-separated list ofname:Typedeclarationsdir: the directory containing that collection's Markdown filestemplate: optional path to the.htmlpage template for that collection
Example:
[projects]
schema = title:String, status:String, description:Optional[String]
dir = example/content/projects
template = example/templates/project-page.htmlIf template is set, lattice uses that file for pages in the collection instead of the site-wide page.html. If template is omitted, the collection uses the site-wide page template as before. output_dir is still not configurable per collection; output paths are derived from the collection name.
The example site has both posts and projects:
postsreads fromexample/content/postsprojectsreads fromexample/content/projects
They coexist cleanly because each collection has:
- its own schema
- its own source directory
- its own output root under
dist/<collection>/
That gives you separate URLs like:
/posts/welcome-lattice//projects/docs-portal/
and separate collection index pages like:
/posts//projects/
The two example collections deliberately model different content:
[posts]
schema = title:String, date:String, tags:Optional[Array[String]], draft:Optional[Bool]
dir = example/content/posts
[projects]
schema = title:String, status:String, description:Optional[String]
dir = example/content/projectsThat means:
- posts must have
titleanddate - posts may have
tagsanddraft - projects must have
titleandstatus - projects may have
description
This is why lattice can treat content integrity as a build-time property. A project page cannot accidentally look like a blog post, because the collection schema rejects that mismatch before rendering.
The [data.*] sections are related but separate from content collections:
[data.nav]
required = title,subtitle,cta
[data.site]
required = owner,footerThese sections validate TOML-style files loaded from data_dir. They matter because templates can reference values like {{data.nav.title}} and {{data.site.footer}}. If a required data key is missing, the build fails instead of rendering a broken template.
Collection output is generated from the collection name, not from a custom output_dir setting.
For the example site:
postspages render underdist/posts/<slug>/index.htmlprojectspages render underdist/projects/<slug>/index.html- each collection also gets
dist/<collection>/index.html - each collection gets
dist/<collection>/feed.xml
If page_size forces pagination, lattice adds:
dist/<collection>/page/2/index.htmldist/<collection>/page/3/index.html
If you do not pass a collections file, lattice falls back to a default posts collection rooted at the content directory. That is useful for experiments, but real sites should define collections explicitly so the schema is obvious and versioned.
To build the checked-in example collections:
moon run cmd/main -- ./example/content ./dist --config ./example/site.cfg --collections ./example/collections.cfgTo add another collection, create a new section with a unique name and directory. As long as the source files satisfy the schema, it becomes another first-class content type in the build, navigation, feeds, and search index.