Say goodbye to Durable Object migration tags — meet the new declarative exports
Hi there, it's Shii! Today I found a small but genuinely nice update on the Cloudflare Changelog about Durable Objects. It's about your config file getting a lot tidier, so let's dig in!
Cloudflare ChangelogWhat was announced?
Cloudflare's Changelog announced a new exports field for your Wrangler configuration file. It replaces the old imperative migrations array as the way you manage a Durable Object class's lifecycle, switching to a declarative model instead.
You declare each Durable Object class your Worker exports, and Cloudflare compares that declaration against what is already deployed to figure out which classes need to be created, renamed, or deleted.
The story so far
Until now, managing a Durable Object class's lifecycle meant building up an ordered list of tagged steps inside the migrations array.
For example, renaming a class from ChatRoom to Room required keeping both of these tagged steps around:
{
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["ChatRoom"] },
{
"tag": "v2",
"renamed_classes": [{ "from": "ChatRoom", "to": "Room" }]
}
]
}
You had to keep maintaining a chain of v1, v2, v3, and so on, and the config file only kept growing and getting harder to follow.
What changes
With exports, instead of piling up a history chain, you only declare the current state. The same rename example now looks like this:
{
"exports": {
"ChatRoom": {
"type": "durable-object",
"state": "renamed",
"renamed_to": "Room"
},
"Room": { "type": "durable-object", "storage": "sqlite" }
}
}
The exports map becomes the single source of truth, so you don't have to carry old tags like v1 and v2 forever. On top of that, Wrangler reports which classes it created, updated, deleted, renamed, or transferred on every deploy, in a structured way, so it's much easier to see exactly what changed.
Dive Deep
Each entry in exports is keyed by class name, and the state field carries the lifecycle status:
created(the default): a currently live classdeleted: a deleted (tombstoned) classrenamed: a class that has been renamedtransferred: a class transferred to another Workerexpecting-transfer: the receiving side of a cross-Worker transfer
The key idea is that these "no longer active" tombstone states can coexist with the classes in your source code, which avoids runtime errors mid-rollout and enables zero-downtime renames and transfers.
There's a safety net built in too: when you delete or rename a class, Cloudflare enumerates every other Worker in your account that still references that namespace, so you can redeploy them before the change lands. That should help you avoid accidentally breaking a Worker that still has a stray reference.
Existing Workers using the migrations array keep working exactly as before, so there's no rush to migrate. Cloudflare has a migration guide ready for when you do want to switch over. One thing to note: exports and migrations are mutually exclusive within a single Worker, so you can't mix the two.
Wrap-up
- Durable Object class lifecycle management now has a declarative
exportsfield alongside the imperativemigrationsarray - You no longer build up a tag history; the
exportsmap is the single source of truth statesupports five values:created,deleted,renamed,transferred, andexpecting-transfer- Renames and transfers can happen with zero downtime, and Cloudflare automatically flags other Workers that still reference the old namespace
- Existing
migrations-based Workers keep working unchanged, and migrating is optional — just rememberexportsandmigrationscan't be mixed in the same Worker
If you've been juggling Durable Object class renames and migration tags, this update is worth trying out!