Meridian handbook
Concepts

Stable ids

The id written beside every named element in Meridian configuration, who writes it, why a rename keeps all stored data, how renames and aliases work, and how to fix a missing, copied or wrong id.

Every named element in a project’s configuration carries an id: beside its handle. The handle (a key, name or code) is a label you can change at any time; the id is the element’s identity. The database stores everything by id, so renaming a field, a type, a site or a route keeps every value stored under it.

fields:
  - { name: lengthKm, aliases: [distance], id: fld_qvbnm6shzg, type: number }

Here the field was called distance and is now lengthKm. Its id did not change, so every document’s value is still there, and the old handle still answers as an alias.

The rules

  1. Never type an id and never copy one. The tooling writes ids. An element you add by hand gets one from engine-dmo check --fix, engine-dmo dev up, or the engine-dmo dev verb that adds it.
  2. Never edit an id. A changed id is a different element: the plan replaces the stored one.
  3. Change the handle freely. A changed handle beside an unchanged id is a rename.
  4. Ids are per project. engine-dmo init --from gives a copied project new ids so the two can never be confused.

check cannot tell a typed id from a written one: any well-formed id passes, so rule 1 is yours to keep.

schema plan compares each element in the files with the stored one by id first, then by handle:

flowchart TD
  el["An element in the files"] --> hasid{"Has an id?"}
  hasid -- no --> fix["check refuses it:<br/>run check --fix"]
  hasid -- yes --> stored{"Id stored?"}
  stored -- yes --> samehandle{"Same handle?"}
  samehandle -- yes --> same["No change, or ~ change"]
  samehandle -- no --> rename["> rename: values kept"]
  stored -- no --> oldhandle{"Handle stored?"}
  oldhandle -- no --> add["+ add"]
  oldhandle -- "yes, with no id" --> bind["= bind"]
  oldhandle -- "yes, under another id" --> replace["! replace: refused<br/>without --replace"]

What an id looks like

A prefix naming the kind of element, an underscore, and ten characters from a lower-case base32 alphabet without i, l, o or u: fld_qvbnm6shzg. The prefix makes an id of the wrong kind an obvious error.

PrefixElementWhere
site_A sitesite.id in sites/<key>/site.yaml
net_A networknetworks.yaml
loc_A localelocales.yaml
grp_A locale group, or a group of fields in a type’s editorlocales.yaml, schema files
typ_A content typeSchema files
fld_A field, including custom CRM and staff user fieldsSchema files, crm/, access/users.yaml, portal/enquiries.yaml
blk_A blockblocks/_index.yaml, schema files
opt_A select option, or a link styleSchema files: { value: mid, id: opt_... }
var_An entry variantSchema files
rte_A routeroutes.yaml
lnd_A landing page pairingroutes.yaml
nav_A navigation slotsite.yaml
end_A declared endpointendpoints.yaml
src_, imp_, whk_A source, an importer, a webhooksources.yaml, importers.yaml, webhooks.yaml
role_A staff role or a partner roleaccess/roles.yaml, portal/roles.yaml
rep_A reportanalytics/reports.yaml
met_An entered metricanalytics/dashboards.yaml
tier_A membership tiermemberships.yaml
scr_, act_A portal screen, a portal actionA site’s portal.yaml
slot_A promotion slotA site’s promotions.yaml

A role that replaces a built-in role (same key) needs no id: it keeps the built-in role’s.

Writing ids

check refuses an element without an id:

config/sites/main/routes.yaml:2:11: route "page" has no id
    2 |   - type: page
      |           ^^^^
      = run engine-dmo check --fix to write one; ids are written by the tooling, never by hand
      = error code MRD-1006

check --fix writes every missing id, keeping your comments and layout, then checks:

engine-dmo check --no-db --fix
wrote 1 id in 1 file
routes:
  - type: page
    id: rte_4rvbbqzx1m
    uri: "/{slug}"

engine-dmo dev up does the same on every save, and every engine-dmo dev verb writes the id of the element it adds. An element written as an empty map, such as a navigation slot main: {}, cannot take an id (check --fix says nav.main is an empty mapping); give it at least one setting first, such as main: { depth: 1 }.

Renaming

Rename with a verb where there is one: it changes the handle, keeps the id, and rewrites every reference to the handle in your configuration.

engine-dmo dev field rename walk distance lengthKm
wrote config/schema/walk.yaml
field.walk.lengthKm: fld_qvbnm6shzg
walk.distance answers as an alias until engine-dmo schema alias retire walk.distance
RenameCommandWhat else happens
A fielddev field rename <type> <old> <new>The old handle is kept in aliases: so templates using it keep working. --no-alias drops it
A sitedev site rename <old> <new>The site’s directory moves; old admin and public URLs redirect
A source, importer or webhookdev source rename, dev importer rename, dev webhook renameEvery endpoint step naming it is rewritten
Anything elseEdit the handle in the file, leave the idschema plan shows it as a rename

schema plan marks a rename with >, and applying it changes only the stored handle. describe type shows a field’s old handle (number [translate none, was distance]).

Field aliases

An alias keeps an old field handle working in templates (and, on engine-dmo, the member API). List and retire them when nothing uses the old handle:

engine-dmo schema alias list
engine-dmo schema alias retire walk.distance

retire refuses while a template still uses the alias. engine-dmo dev status lists the live aliases dev up found.

Mistakes and how to fix them

ProblemWhat check or the plan saysFix
An element has no idroute "page" has no idengine-dmo check --fix
The same id on two elements (usually a copied block)id fld_... is written on two elements: field "title" here and field "summary" at ...Delete the copy’s id and run check --fix
An id of the wrong kindtyp_... is a type id; a field id starts fld_Delete it and run check --fix
A malformed id"fld_abc" is not an id: after fld_ come 10 characters, not 3Delete it and run check --fix
An existing handle with a new idThe plan marks it ! (replace) and schema apply refuses itPut the stored id back (your version control history has it), or apply with --replace <type>.<field> when you mean a new element

A replace drops the stored element and creates a new one, so the values stored under the old id are no longer read by the field. Treat every ! in a plan as a mistake until you are sure.

Databases made before ids

A database whose schema was applied from files that had no ids can take the ids the files now carry without changing anything else:

engine-dmo schema adopt-ids

It writes any missing ids (as check --fix does), then applies a plan that may contain only binds (=): each stored element takes the id its file gives it. A plan with any other change is refused; apply that first with schema apply.

Ids in the rest of the engine

  • engine-dmo describe project and describe type <key> print every element with its id, as text or --json.
  • engine-dmo guide lists each site, type and field with its id, so an agent working on the project can refer to them.
  • Documents have UUIDs, not configuration ids. They are stored in the database and never appear in configuration or seed files.
  • A seed file may hold a configuration id where a field’s value is one: a form field stores its endpoint’s id, so a seed writes contactForm: end_srhmvkf6j3, copied from endpoints.yaml or describe project. Copying an id that the tooling wrote into the value that refers to it is not inventing one.