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.
Directory Location
Section titled “Directory Location”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.
Filename Convention
Section titled “Filename Convention”Every metadata file follows this pattern:
<moduleKey>_<qualifiedPath>_<metadataType>.json5The 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 |
File Types
Section titled “File Types”| 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 |
How the Loader Parses Filenames
Section titled “How the Loader Parses Filenames”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 Definition Files
Section titled “Seed Definition Files”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.json5The body is a SeedDefinition JSON5 object — access, key,
and data at the top level (no objectKey wrapper):
{ access: "vendor", key: "value", data: [ { value: "active", label: "Active" }, { value: "draft", label: "Draft" }, ],}Rules:
- Exactly one
*_seed.json5per object. A second file for the same object is a hard load error. - The
ObjectKeyqualifier in the filename must match an authored*_object.json5or a synthesized junction object. A seed file for a non-existent object is a hard load error. - Inline
seed:in*_object.json5is not allowed. The loader rejects any object file that carries aseedkey with a diagnostic naming the correct*_seed.json5migration path.
Error Behavior
Section titled “Error Behavior”- 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.json5file targets a non-existent object, loading fails with an error naming the qualifiedmodule.Objectthat could not be found. - If an
*_object.json5body contains an inlineseed:key, loading fails with a migration-pointer message.
Example Directory Tree
Section titled “Example Directory Tree”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.json5See Also
Section titled “See Also”- Concept: From Metadata to Database – the authoring loop this directory structure supports
- Module Manifest – properties of
*_module.json5files - Object Definition – properties of
*_object.json5files - Field Kinds – properties of
*_field.json5files - Seed Definition – properties of
*_seed.json5files - Metadata and Apply Pipeline – how the loader fits into the compilation pipeline