Durable Objects, Workers - Declare Durable Object class lifecycle with `exports`
- Announced
- Tags
- Durable-Objects, Workers
- Severity
- info, set by
reef/rss-rule-v1 - Source
- https://developers.cloudflare.com/changelog/post/2026-06-30-declarative-do-class-exports/
<p>A new declarative <a href="https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/"><code>exports</code></a> field in your Wrangler configuration file replaces the imperative <a href="https://developers.cloudflare.com/durable-objects/reference/durable-object-class-migrations-legacy/"><code>migrations</code></a> array for managing Durable Object class lifecycle. Instead of writing an ordered list of migration steps with unique tags, you declare each Durable Object class your Worker exports and Cloudflare compares that against what's already deployed to determine what Durable Object state needs to be created, renamed, or deleted.</p> <p>With legacy migrations, renaming <code>ChatRoom</code> to <code>Room</code> requires retaining both tagged steps:</p> <figure class="nb-code-figure nb-code-figure-titled" data-nb-lang="jsonc"><figcaption class="nb-code-title"><span class="nb-code-title-name">Before — legacy migrations</span><span class="nb-code-title-lang">jsonc</span></figcaption><pre class="astro-code astro-code-themes github-light github-dark nb-shiki-c6xiwz" tabindex="0" data-language="jsonc" data-nb-lang="jsonc"><code><span class="line"><span class="nb-shiki-140thh">{</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "migrations"</span><span class="nb-shiki-140thh">: [</span></span> <span class="line"><span class="nb-shiki-140thh"> { </span><span class="nb-shiki-dzsirb">"tag"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"v1"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-dzsirb">"new_sqlite_classes"</span><span class="nb-shiki-140thh">: [</span><span class="nb-shiki-mdbnqw">"ChatRoom"</span><span class="nb-shiki-140thh">] },</span></span> <span class="line"><span class="nb-shiki-140thh"> {</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "tag"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"v2"</span><span class="nb-shiki-140thh">,</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "renamed_classes"</span><span class="nb-shiki-140thh">: [{ </span><span class="nb-shiki-dzsirb">"from"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"ChatRoom"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-dzsirb">"to"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"Room"</span><span class="nb-shiki-140thh"> }],</span></span> <span class="line"><span class="nb-shiki-140thh"> },</span></span> <span class="line"><span class="nb-shiki-140thh"> ],</span></span> <span class="line"><span class="nb-shiki-140thh">}</span></span></code></pre></figure> <p>With <code>exports</code>, you instead declare <code>Room</code> as the current class and mark <code>ChatRoom</code> as renamed:</p> <figure class="nb-code-figure nb-code-figure-titled" data-nb-lang="jsonc"><figcaption class="nb-code-title"><span class="nb-code-title-name">After — declarative exports</span><span class="nb-code-title-lang">jsonc</span></figcaption><pre class="astro-code astro-code-themes github-light github-dark nb-shiki-c6xiwz" tabindex="0" data-language="jsonc" data-nb-lang="jsonc"><code><span class="line"><span class="nb-shiki-140thh">{</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "exports"</span><span class="nb-shiki-140thh">: {</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "ChatRoom"</span><span class="nb-shiki-140thh">: {</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "type"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"durable-object"</span><span class="nb-shiki-140thh">,</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "state"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"renamed"</span><span class="nb-shiki-140thh">,</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "renamed_to"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"Room"</span><span class="nb-shiki-140thh">,</span></span> <span class="line"><span class="nb-shiki-140thh"> },</span></span> <span class="line"><span class="nb-shiki-dzsirb"> "Room"</span><span class="nb-shiki-140thh">: { </span><span class="nb-shiki-dzsirb">"type"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"durable-object"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-dzsirb">"storage"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"sqlite"</span><span class="nb-shiki-140thh"> },</span></span> <span class="line"><span class="nb-shiki-140thh"> },</span></span> <span class="line"><span class="nb-shiki-140thh">}</span></span></code></pre></figure> <p>Each entry is keyed by class name. The <code>state</code> field carries the lifecycle (<code>created</code> by default — a live class — plus tombstone states <code>deleted</code>, <code>renamed</code>, and <code>transferred</code>, and the <code>expecting-transfer</code> receiving state for cross-Worker transfers).</p> <p>Key improvements over the legacy <code>migrations</code> array:</p> <ul> <li><strong>No migration tags.</strong> The current <code>exports</code> map is the source of truth — there is no historical chain of <code>v1</code>, <code>v2</code>, <code>v3</code> entries to maintain.</li> <li><strong>Structured deployment output.</strong> Wrangler reports when it creates, updates, deletes, renames, or transfers Durable Object classes. It also identifies stale configuration entries that are safe to remove. Deployments with no changes or notices do not print this output.</li> <li><strong>Zero-downtime rename and transfer patterns are first-class.</strong> Tombstones may coexist with the source class still in code, enabling a <a href="https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/#avoid-downtime-during-a-rename">three-deploy rename</a> and a <a href="https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/#transfer-a-durable-object-class-between-workers">four-deploy cross-Worker transfer</a> without runtime errors during the rollout window.</li> <li><strong>Cross-Worker safety.</strong> When you delete or rename a class, Cloudflare lists every other Worker in your account whose bindings still reference the namespace, so you can redeploy them before the change goes live.</li> </ul> <p>Existing Workers using the legacy <a href="https://developers.cloudflare.com/durable-objects/reference/durable-object-class-migrations-legacy/"><code>migrations</code></a> array continue to work unchanged. To move to <code>exports</code>, refer to the <a href="https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/#migrate-from-the-legacy-migrations-flow">migration guide</a>. <code>exports</code> and <code>migrations</code> are mutually exclusive within a single Worker.</p> <p>For the full reference, refer to <a href="https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/">Durable Object class exports</a>.</p>
The text above is the source's. reef added the severity, the dates it could read from the text, and the endpoints and scopes named in code.