Schema Migration

Apply data model changes to a project and import changes made directly in a data source through the schema migration endpoints.

Overview

The schema migration endpoints change a project's data model over the REST API. A migration is an ordered list of operations that create, rename, update, or delete the building blocks of the model: namespaces, collections, fields, indexes, and relations.

Two endpoints cover the full workflow. One applies a migration you author; the other imports changes made directly in a data source.

  • namespace — a schema in the underlying data source, grouping related collections
  • collection — a container for items of the same type
  • field — a named value on an item
  • data source — a database Monospace connects to, identified by its ID

The Two Endpoints

MethodEndpointPurpose
POST/api/{project}/schema/migrateApply a migration you author.
POST/api/{project}/schema/introspect/{source}Import schema changes made directly in a data source.

Pick the endpoint by where the change originated.

Where the change originatedEndpointGuide
You designed it (add a collection, drop a field, create an index)/schema/migrateApply Migrations
The data source changed outside Monospace (a collection or field added in SQL)/schema/introspect/{source}Import Changes

Authentication

Both endpoints require the DataModel edit entitlement on the project. Send an access token that carries it in the Authorization header. Project admins hold this entitlement by default. See Access Control for how entitlements are granted.

terminal
Authorization: Bearer YOUR_API_KEY

Migration Format

Every operation is adjacently tagged: a kind string names the operation and a data object carries its payload.

operation.json
{
  "kind": "createCollection",
  "data": { "...": "..." }
}

Operations nest. createCollection and updateCollection hold field and index operations in their own data.operations array, and updatePrimitiveField holds field-change operations. The Operation Reference documents every kind.

New entities carry a client-generated id — a UUID you mint and reuse to reference the entity in later operations. Existing entities use the IDs already in the schema.

Within a collection, the nested field and index operations are sorted into a safe order. Top-level operations run in the order you send them — sequence dependent operations yourself.

Finding IDs

Operations reference the data source and existing entities by ID. Mint a fresh UUID for anything you create; look up the rest.

The data source ID — used as sourceId and as the {source} path parameter — is returned when you create a source through POST /api/{project}/sources/data. The response carries it at data.id:

response.json
{ "data": { "id": "d7c8f0e2-9b3a-4c1e-8f2a-1a2b3c4d5e6f" } }

IDs of existing collections, fields, namespaces, indexes, and relations are readable through the system collections that hold the data model, using the standard item API:

ReadItem API path
Data sourcesGET /api/blog/items/MonospaceDataSource
NamespacesGET /api/blog/items/MonospaceNamespace
CollectionsGET /api/blog/items/MonospaceCollection
FieldsGET /api/blog/items/MonospacePrimitiveField
Relation fieldsGET /api/blog/items/MonospaceSingleRelationField
IndexesGET /api/blog/items/MonospaceIndex

There is no list endpoint under /sources/data — read MonospaceDataSource to enumerate existing sources.

How Migrations Apply

Applying a migration is a two-phase operation guarded by a per-project write lock. Monospace first persists the updated model to its system database inside a transaction, then applies the changes to the data source. If the data source step fails, Monospace rolls back the system transaction.

Monospace does not provide a rollback guarantee for data source changes. A failed migration can leave a data source partially changed, including a migration that targets one source. Re-introspect the source before sending another migration. A migration that spans multiple data sources can also leave sources in different states.

The write lock serializes schema changes within a project. Migrations on different projects run in parallel; migrations on the same project queue. See Concurrent Migrations for the single-instance requirement.

Errors

The endpoints can return these status codes.

StatusMeaning
401The access token is invalid or expired.
403The caller lacks the DataModel edit entitlement.
404The project does not exist. /schema/introspect/{source} also returns 404 when the source does not exist.
422The /schema/migrate request JSON is malformed, has unknown or empty fields, or contains an invalid API name. The response body names the offending path for JSON errors.
413The /schema/migrate request body exceeds the configured size limit.
500The migration or introspection failed to execute. Semantic checks applied while the migration runs — such as an invalid default value — also return 500.

A 422 response points at the exact field that failed:

response.json
{
  "message": "Failed to deserialize the JSON body into the target type: operations[0]: data.dbName: Value must not be empty at line 1 column 174"
}

See Also

Copyright © 2026