BlogPost can reference an Author, a Page can reference related BlogPost entries, and so on. MDCMS handles storage, validation, and resolution of these relationships.
Defining references
Use thereference() helper to create a reference field. It accepts the target type name as a string:
mdcms.config.ts
reference() returns a z.string() schema with metadata that marks it as a reference to the target type. This means reference fields support the same modifiers as strings: .optional(), .nullable(), and .default().
What gets stored
Reference fields store a documentId (UUID) in frontmatter, not a file path or slug. When you create or update a document through Studio or the API, MDCMS validates that the referenced documentId exists, belongs to the correct type, and has not been deleted.The server validates reference identity on every write. If you supply a
documentId that doesn’t exist, belongs to a different type, or references a
deleted document, the write will fail with an
INVALID_INPUT error.Resolving references
By default, the API returns the raw documentId string for reference fields. To expand references into full document objects, use theresolve query parameter.
Resolved response structure
When a reference is resolved successfully, the raw UUID is replaced with the full document response object:Nested field paths
You can resolve references inside nested objects using dot notation:INVALID_QUERY_PARAM error.
Shallow resolution
Reference resolution is one level deep only. If a resolved document itself contains reference fields, those nested references are returned as raw documentId strings, not expanded. For example, ifAuthor had a team: reference("Team") field, resolving author on a BlogPost would return the Author document with team as a UUID string. To get the Team document, you would need a separate API call.
Resolve errors
If a reference cannot be resolved, the field value is set tonull and an entry is added to the resolveErrors map in the response. This map is keyed by the full frontmatter path (e.g., frontmatter.author).
Error codes
| Code | Description |
|---|---|
REFERENCE_NOT_FOUND | The referenced document does not exist in the target project/environment. |
REFERENCE_DELETED | The referenced document has been soft-deleted. |
REFERENCE_TYPE_MISMATCH | The referenced document exists but belongs to a different type than the reference field expects. |
REFERENCE_FORBIDDEN | The referenced document exists but is not readable with the current API key scope. |
Studio behavior
In Studio, reference fields render as a document picker filtered by the target type. When editing a BlogPost with anauthor: reference("Author") field, the picker shows only Author documents.
Search or browse
Filter by title or browse the list. Only documents matching the target type
are shown.
Multiple references
Usez.array(reference("TypeName")) for one-to-many relationships: