Skip to main content
View as Markdown

Multi-File Configs with $ref

One file stops being readable somewhere around the third table. $ref splits a YAML or JSON config across as many files as you like, with no change to the resulting object.

Any object whose only key is $ref, and whose value is a relative path, is replaced by the parsed contents of that file.

# app.yaml
name: crm-workspace
version: 2.0.0

auth:
  $ref: ./config/auth.yaml

theme:
  $ref: ./config/theme.yaml

tables:
  - $ref: ./config/tables/companies.yaml
  - $ref: ./config/tables/contacts.yaml
  - $ref: ./config/tables/deals.yaml

pages:
  - $ref: ./config/pages/sign-in.yaml
  - $ref: ./config/pages/companies.yaml

agents:
  - $ref: ./config/agents/records-assistant.yaml
# config/tables/companies.yaml
id: 1
name: Companies
fields:
  - { id: 1, name: name, type: single-line-text, required: true }
  - { id: 2, name: website, type: url }

Rules

Rule Behavior
Path resolution $ref paths resolve relative to the file that contains them, not the working directory.
Mixed formats A YAML root file may $ref a JSON partial and vice versa — each file is parsed by its extension.
Array elements A $ref can stand in for a whole array element (- $ref: ...) or a whole object value.
Resolution timing All $refs are resolved into one object before schema validation, so cross-section checks see the full app.

Resolving before validation is what makes splitting safe: a rule such as "a record automation must reference an existing table" is still checked across the whole app, even when the automation and the table live in different files.

The config/ convention

sovrium init scaffolds — and the bundled templates follow — one shape: one file per collection entity, one file per singleton, scalars stay inline.

app.yaml               # name, version, and the $ref map
config/
  auth.yaml            # singleton
  theme.yaml           # singleton
  tables/
    companies.yaml     # one entity per file
    contacts.yaml
  pages/
    sign-in.yaml

Nothing enforces this layout — $ref accepts any relative path. It earns its keep by making the root file a table of contents: what the app contains is legible without opening anything else.

When to split

Keep a config in one file while it is small. Split once a section grows big enough to deserve its own name — in practice, past the first couple of tables or pages, or as soon as a theme gets substantial.

Validation attributes errors back to the file they came from, so a mistake in a partial is reported against that partial rather than against the root:

Validation failed:
  companies.yaml: Unknown field type "web-site" in field "website"

Last updated July 27, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta — contributions and corrections are welcome.

Built with Sovrium