Edits and migrations
An edit that would leave records invalid is refused with
requires_migration (or requires_backfill), pointing you to a migration.
Which values convert
- Any type converts to
json, andjsonto any type whose values it already holds (a string becomes rich text as Markdown). - Numbers, booleans, dates and enum values convert to
textandlong_text. textandlong_textconvert to each other, and tointeger,decimal,boolean(trueorfalse),dateandenumwhen the value fits, and torich_text, with a paragraph per block of text between blank lines.integerconverts todecimal, anddecimaltointegerwhen the value is a whole number.
incompatible_type). Turning multiple on makes each value a list of one. Turning it off keeps lists of one value; longer lists can’t convert. Adding a date’s time makes each date midnight in the field’s time zone (UTC without one); removing it keeps the day each moment falls on, in the time zone you choose (by default the field’s, else UTC).
Preview
A preview checks every record, deleted ones included, and writes nothing. It gives:conversion:safe(every value converts, with the same meaning),convertible(every value converts, in another form) orconditional(some values may not convert);- how many records end up
unchanged,converted,backfilled,clearedorinvalid; - up to 10 sample records with their values before and after, invalid ones first.
deleted_at): restore and fix them, or clear their values. A migration to a unique field is refused with duplicate_values while converted values or the backfill would be shared.
In the web app
Open the collection’s Schema tab and configure the field:- Pick another Type, or turn Include time on or off, and the Migrate field dialog opens. Choose the new settings, then Preview.
- Turning Multiple values off opens the preview straight away. Turning it on skips the preview, since every value converts: the migration starts when you save.
- When Required can’t be turned on because records have no value, choose Fill empty values… and enter a Value for records without one.
Through the API
Find the field’s ID (GET /v1/collections/{collection_id}/fields), then preview the change with dry_run=true:
dry_run, the API checks every record again and refuses with 422 if any is invalid. Otherwise it answers 202 with a migration (mig_…) whose status goes from pending to running to complete, failed or cancelled: follow it with GET /v1/migrations/{migration_id}.
The body names only what changes: type, multiple, required or configuration (the complete new one; with a new type and none given, only the help text and search settings carry over). backfill fills in records without a value, on_invalid: "clear" clears values that can’t convert, and time_zone says whose day a moment becomes when a date loses its time. A dry run shows record values, so it needs records:read as well as schema:write. Add a reason with the Nohead-Change-Note header. The API reference has every parameter.
While it runs
- From the start, the collection’s fields can’t change: schema writes are refused with
409(migration_in_progress). While a migration ispending(queued, not started yet), records can still be edited; a new value that can’t convert fails it (or is cleared, withon_invalid: "clear"). - Once it is
running, record writes are refused with409too. Reads are never affected: clients see the old values until the migration completes, then every new value at once. - Drafts’ values for the field are converted as well; a value that can’t be is dropped from its draft. Scheduled publishes and merges that come due while it runs are made once it finishes.
nohead migrations cancel mig_… or POST /v1/migrations/{migration_id}/cancel. A pending one stops at once; a running one is rolled back entirely at its next batch, with cancel_requested_at set until then. A migration that fails changes nothing either, and its failure.message says why.
Results and history
A completed migration’srecords counts each outcome. Each record whose value changed gets a migrate revision, so its old value stays in its history (Migrated in the web app). The collection’s schema history, on its History tab or at GET /v1/collections/{collection_id}/schema-changes, has a migrate_field change (the migration’s schema_change_id), and GET /v1/collections/{collection_id}/migrations lists its migrations, newest first.
A completed migration sends one field.migrated webhook event, not a record.updated per record, so a site that rebuilds on record changes should listen for field.migrated too.