Records

Your pages are your database: each page declares its own entry in one or more collections as a record — a small block of typed fields that other pages pull into listings and counts. A blog post might declare its record like this:

<!-- localhoster:record collection="blog" -->
  <!-- localhoster:record-field name="title" type="text"
       ```
       Drop a folder, get an HTTPS site
       ``` -->
  <!-- localhoster:record-field name="date" type="text" value="2026-06-20" -->
  <!-- localhoster:record-field name="reading-minutes" type="integer" value="4" -->
  <!-- localhoster:record-field name="featured" type="boolean" value="true" -->
  <!-- localhoster:record-field name="summary" type="html"
       ```
       <p>Name a folder for its domain, served over HTTPS.</p>
       ``` -->
<!-- localhoster:/record -->

Record

A page can be part of any number of collections, and can hold more than one record for the same collection, so one page can contribute several entries to a list. On each page that should appear in lists, open a record block naming its collection:

ParameterDescription
collectionthe collection this record joins; other pages list and count by it

Fields

Inside the record, declare each field with a record-field: a name, an optional type, and a value given by either value="…" (kept verbatim, spaces and all) or a fenced ``` block (trimmed):

ParameterDescription
namethe field name — used as {{name}} and in filters, sorts and groups
typeone of the types below (default auto)
valuethe value, kept verbatim; omit it to use a fenced ``` block instead, which is trimmed

Field Types

A field’s type decides two things: how it is compared by filters, sorts and groups (so numbers behave as numbers, not text where "10" < "9"), and how its value is written into a template. Every value is HTML-escaped so a field’s text can never inject markup — except html, which is inserted raw, for fields that hold real markup:

TypeDescription
textplain text, HTML-escaped on output; compared exactly and lexicographically
htmlinserted raw, not escaped, for values that are real HTML markup; compared as text
integerwhole numbers; numeric comparison and equality
numbernumbers with decimals; numeric comparison
booleantrue / yes / 1 / on are true, anything else false
autountyped (the default): numeric where the value looks numeric, otherwise text
Values are checked against their type when the automation runs: a value that does not fit (a non-numeric integer, say) is reported with its page and field, and the site is left unchanged until it is fixed.

Fields are invisible

The values live only in the comments, never wrapped around page markup, so a record is not limited to what the page shows: a field can be a date, a sort key, a thumbnail URL or a summary that appears nowhere on the page itself. The record’s own path is its key.

Errors

Every record is validated before the site is written; a problem is reported against the page and the field, and the site is left unchanged until it is fixed (other sites still run):

MessageWhen it appears
record "…" may only contain record-field (found …)a record block holds some other comment
record "…": a record-field needs name="…"a record-field with no name
record-field "…": type="…" is not one of text, html, integer, number, boolean, autoan unknown type
record-field "…": type="integer" but value "…" is not a whole numberan integer value that is not a whole number
record-field "…": type="number" but value "…" is not a numbera number value that is not numeric
record-field "…": type="boolean" but value "…" is not a boolean (true/false)a boolean value that is not true/false
record-field "…": missing a ``` value blockneither value="…" nor a fenced block to read the value from

Next steps