Skip to content

Metadata File Layout

Henceforth metadata is authored as JSON5 files under a configured metadata root directory. The runtime loads these files at startup and during /plan and /apply operations.

The runtime accepts one metadata root path. In this repository, the working metadata set lives at:

dev/metadata/

The loader walks this directory recursively and reads every file with a .json5 extension. Subdirectories are allowed but have no semantic meaning – the filename alone determines how each file is interpreted.

Every metadata file follows this pattern:

<moduleKey>_<qualifiedPath>_<metadataType>.json5

The three segments are separated by underscores, with the metadata type always last:

Segment Description Examples
moduleKey The module identifier. May contain dots for vendor-prefixed modules. core, acme.crm
qualifiedPath The object key (for object, seed, and relationship files) or ObjectKey.fieldKey (for field files). Absent for module files. Account, Contact.email
metadataType One of the fixed values: module, object, field, relationship, or seed. module, object, field, seed
Metadata Type Filename Pattern Example
Module manifest <moduleKey>_module.json5 core_module.json5
Object definition <moduleKey>_<ObjectKey>_object.json5 core_Account_object.json5
Field definition <moduleKey>_<ObjectKey>.<fieldKey>_field.json5 core_Contact.email_field.json5
Relationship definition <moduleKey>_<relationshipKey>_relationship.json5 core_accountOwner_relationship.json5
Seed definition <moduleKey>_<ObjectKey>_seed.json5 core_Status_seed.json5

The loader splits the filename (without extension) on underscores to extract the module ID, qualified path, and metadata type.

For a field file like core_Contact.account_field.json5:

Extracted value Result
Module ID core
Object key Contact
Field key account
Metadata type field

For a vendor-prefixed module like acme.crm_Order.quantity_field.json5:

Extracted value Result
Module ID acme.crm
Object key Order
Field key quantity
Metadata type field

The dot in acme.crm is part of the module ID (vendor prefix). The dot in Contact.account separates the object key from the field key.

Seed data (pre-populated records upserted by the apply engine) is authored in a separate *_seed.json5 file rather than inline in the object file. This keeps the object file focused on its schema and allows junctions (relationship-owned objects without their own *_object.json5) to carry seed data by the same mechanism.

<moduleKey>_<ObjectKey>_seed.json5

The body is a SeedDefinition JSON5 object — access, key, and data at the top level (no objectKey wrapper):

core_Status_seed.json5
{
access: "vendor",
key: "value",
data: [
{ value: "active", label: "Active" },
{ value: "draft", label: "Draft" },
],
}

Rules:

  • Exactly one *_seed.json5 per object. A second file for the same object is a hard load error.
  • The ObjectKey qualifier in the filename must match an authored *_object.json5 or a synthesized junction object. A seed file for a non-existent object is a hard load error.
  • Inline seed: in *_object.json5 is not allowed. The loader rejects any object file that carries a seed key with a diagnostic naming the correct *_seed.json5 migration path.
  • If a filename cannot be parsed into the expected segments, the file is skipped with a warning.
  • If a filename parses correctly but the JSON5 body is malformed or missing required properties, loading fails with a structured diagnostic that includes the source file path.
  • If a *_seed.json5 file targets a non-existent object, loading fails with an error naming the qualified module.Object that could not be found.
  • If an *_object.json5 body contains an inline seed: key, loading fails with a migration-pointer message.

A realistic metadata set for a CRM module including seed data:

dev/metadata/
core_module.json5
core_Account_object.json5
core_Account.name_field.json5
core_Account.industry_field.json5
core_Account.email_field.json5
core_Account.active_field.json5
core_Status_object.json5
core_Status.value_field.json5
core_Status.label_field.json5
core_Status_seed.json5 -- seed data for Status
core_Contact_object.json5
core_Contact.firstName_field.json5
core_Contact.lastName_field.json5
core_Contact.email_field.json5
core_Contact.displayName_field.json5
core_Contact.account_field.json5