Data Files
Data files provide structured data that is available to every template on your site. Place YAML, JSON, TOML, or CSV files in the data/ directory and access them through site.data.*.
Supported formats
| Extension | Parser | Result type |
|---|---|---|
.yaml, .yml |
YAML | map[string]any |
.json |
JSON | Ordered map (preserves key insertion order) |
.toml |
TOML | map[string]any |
.csv |
CSV | Array of maps (header row = keys) |
Each file is keyed by its filename without the extension. data/team.yaml becomes site.data.team, data/products.json becomes site.data.products.
Directory structure
Subdirectories create nested namespaces. data/nav/main.yaml becomes site.data.nav.main. Nesting depth is unlimited.
Empty subdirectories are silently skipped — they produce no key in the namespace.
A file and a non-empty directory sharing the same stem (e.g., nav.yaml alongside a nav/ directory containing data files) produces a build error:
Accessing nested data
JSON key order preservation
JSON files preserve key insertion order using an ordered map. This matters when you need deterministic iteration order:
Iterating site.data.sections in a template produces keys in the order intro, setup, usage — matching the file. YAML and TOML files use standard Go maps, which do not guarantee key order. Use JSON when order matters, or add an explicit weight field and sort in the template.
Iterating ordered maps
The iteration syntax differs between template engines:
CSV files
CSV files are parsed with the first row as headers. Each subsequent row becomes a map keyed by the header values:
Access in templates:
Name collision detection
Data files are keyed by stem name (filename without extension). If two files share a stem, the build fails:
No silent overwrites, no priority system. Rename one file to resolve the collision.
External data files
Files outside the data/ directory can be mapped into the data namespace via config:
Each key becomes a site.data.* entry. Paths are resolved relative to the project root:
External data files support YAML, JSON, and TOML — the same formats as data/ directory files except CSV. Pointing an external file at a .csv produces a build error. Use data/ directory placement for CSV files.
External files share the same site.data.* namespace. Moving a YAML, JSON, or TOML file between data/ and external config does not require template changes when the external mapping preserves the same key.
Collision handling
If an external file key matches a data/ directory file stem (e.g., cem key in config and data/cem.json on disk), the build fails with the same collision error. Choose external keys that do not conflict with filenames in data/.
External file not found is a build error – not a warning, not silently skipped.
External data sources
Alloy can fetch data from REST APIs and GraphQL endpoints at build time. Fetched data is injected into site.data.*, making it indistinguishable from local files in templates.
Access fetched data the same way as local files:
Built-in types vs plugin sources
Built-in rest and graphql types are single-request fetchers. They send one HTTP request and parse the response. For anything more complex, use type: "plugin" — see Data Source Plugins.
| Capability | rest / graphql |
plugin |
|---|---|---|
| Single unauthenticated GET | yes | yes |
| Authentication headers | no | yes |
| Pagination | no | yes |
| Custom HTTP methods | no | yes |
| Database access | no | yes |
| Multi-endpoint aggregation | no | yes |
| Retry / error handling | no | yes |
| Environment variables | no | yes |
| Requires Node.js | no | yes |
| Built-in caching | yes | yes |
Caching
All fetched data is cached to .alloy/fetch-cache/ on disk. The cache value sets the TTL in seconds. Cached data survives process restarts. If the TTL has not expired, the cached data is used without fetching.
Combined with virtual pages
Fetched data feeds directly into pagination for page generation:
One template plus an external data source generates pages at build time with no individual content files.
Data in the cascade
Data files sit at the bottom of the Data Cascade. Global data provides site-wide defaults that directory data (_data.yaml) and front matter can override.
Custom data directory
Override the default data/ path in config: