Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ To apply a Create migration:
<Steps>
1. Add the following lines to your `wrangler.toml / wrangler.json` file:

<WranglerConfig>
```toml
[[migrations]]
tag = "<v1>" # Migration identifier. This should be unique for each migration entry
new_classes = ["<NewDurableObjectClass>"] # Array of new classes
# For SQLite storage backend use new_sqlite_classes=["<NewDurableObjectClass>"] instead
```
</WranglerConfig>
The Create migration contains:

- A `tag` to identify the migration.
- The array `new_classes`, which contains the new Durable Object class.
<WranglerConfig>
```toml
[[migrations]]
tag = "<v1>" # Migration identifier. This should be unique for each migration entry
new_classes = ["<NewDurableObjectClass>"] # Array of new classes
# For SQLite storage backend use new_sqlite_classes=["<NewDurableObjectClass>"] instead
```
</WranglerConfig>
The Create migration contains:

- A `tag` to identify the migration.
- The array `new_classes`, which contains the new Durable Object class.

2. Ensure you reference the correct name of the Durable Object class in your Worker code.
3. Deploy the Worker.
</Steps>
</Steps>

<Details header="Create migration example">

Expand All @@ -65,10 +65,12 @@ name = "DURABLE_OBJECT_A"
class_name = "DurableObjectAClass"

# Add the lines below for a Create migration.

[[migrations]]
tag = "v1"
new_classes = ["DurableObjectAClass"]
```

````
</WranglerConfig>

</Details>
Expand Down Expand Up @@ -115,7 +117,8 @@ To delete a Durable Object binding `DEPRECATED_OBJECT`, your `wrangler.toml / wr
[[migrations]]
tag = "v3" # Should be unique for each entry
deleted_classes = ["DeprecatedObjectClass"] # Array of new classes
```
````

</WranglerConfig>
</Details>

Expand All @@ -128,26 +131,27 @@ To apply a Rename migration:
<Steps>
1. Update the previous class name to the new class name by editing your `wrangler.toml / wrangler.json` file in the following way:

<WranglerConfig>
```toml
[[durable_objects.bindings]]
name = "<MY_DURABLE_OBJECT>"
class_name = "<UpdatedDurableObject>" # Update the class name to the new class name
<WranglerConfig>
```toml
[[durable_objects.bindings]]
name = "<MY_DURABLE_OBJECT>"
class_name = "<UpdatedDurableObject>" # Update the class name to the new class name

[[migrations]]
tag = "<v3>" # Migration identifier. This should be unique for each migration entry
renamed_classes = [{from = "<OldDurableObject>", to = "<UpdatedDurableObject>" }] # Array of rename directives
```
</WranglerConfig>
[[migrations]]
tag = "<v3>" # Migration identifier. This should be unique for each migration entry
renamed_classes = [{from = "<OldDurableObject>", to = "<UpdatedDurableObject>" }] # Array of rename directives
```
</WranglerConfig>

The Rename migration contains:
- A `tag` to identify the migration.
- The `renamed_classes` array, which contains objects with `from` and `to` properties.
- `from` property is the old Durable Object class name.
- `to` property is the renamed Durable Object class name.

The Rename migration contains:
- A `tag` to identify the migration.
- The `renamed_classes` array, which contains objects with `from` and `to` properties.
- `from` property is the old Durable Object class name.
- `to` property is the renamed Durable Object class name.
2. Reference the new Durable Object class name in your Worker code.
3. Deploy the Worker.
</Steps>
</Steps>

<Details header = "Rename migration example">

Expand All @@ -162,10 +166,12 @@ name = "MY_DURABLE_OBJECT"
class_name = "UpdatedName"

# Renaming classes

[[migrations]]
tag = "v3"
renamed_classes = [{from = "OldName", to = "UpdatedName" }] # Array of rename directives
```

````
</WranglerConfig>

</Details>
Expand Down Expand Up @@ -221,7 +227,8 @@ class_name = "TransferredClass"
[[migrations]]
tag = "v4"
transferred_classes = [{from = "DurableObjectExample", from_script = "OldWorkerScript", to = "TransferredClass" }]
```
````

</WranglerConfig>

</Details>
Expand All @@ -240,20 +247,21 @@ transferred_classes = [{from = "DurableObjectExample", from_script = "OldWorkerS
- Each migration in the list can have multiple directives, and multiple migrations can be specified as your project grows in complexity.

:::caution[Important]

- The destination class (the class that stored Durable Objects are being transferred to) for a Rename or Transfer migration must be exported by the deployed Worker.

- You should not create the destination Durable Object class before running a Rename or Transfer migration. The migration will create the destination class for you.

- After a Rename or Transfer migration, requests to the destination Durable Object class will have access to the source Durable Object's stored data.

- After a migration, any existing bindings to the original Durable Object class (for example, from other Workers) will automatically forward to the updated destination class. However, any Workers bound to the updated Durable Object class must update their Durable Object binding configuration in the `wrangler` configuration file for their next deployment.
:::
:::

:::note
Note that `.toml` files do not allow line breaks in inline tables (the `{key = "value"}` syntax), but line breaks in the surrounding inline array are acceptable.
:::

{/* ## Examples of Durable Object migration
{/\* ## Examples of Durable Object migration

To illustrate an example migrations workflow, the `DurableObjectExample` class can be initially defined with:

Expand All @@ -268,7 +276,7 @@ new_classes = ["DurableObjectExample"] # Array of new classes

</WranglerConfig>

You can rename the `DurableObjectExample` class to `UpdatedName` and delete an outdated `DeprecatedClass` entirely. You can create separate migrations for each operation, or combine them into a single migration as shown below. */}
You can rename the `DurableObjectExample` class to `UpdatedName` and delete an outdated `DeprecatedClass` entirely. You can create separate migrations for each operation, or combine them into a single migration as shown below. \*/}

## Enable SQLite storage backend on new Durable Object class migration

Expand All @@ -293,3 +301,7 @@ new_sqlite_classes = ["MyDurableObject"] # Array of new classes
For an example of a new class migration, refer to [Get started: Configure Durable Object class with SQLite storage backend](/durable-objects/get-started/tutorial-with-sql-api/#6-configure-durable-object-class-with-sqlite-storage-backend).

You cannot enable a SQLite storage backend on an existing, deployed Durable Object class, so setting `new_sqlite_classes` on later migrations will fail with an error. Automatic migration of deployed classes from their key-value storage backend to SQLite storage backend will be available in the future.

:::caution[Important]
Durable Object migrations are atomic operations and cannot be gradually deployed. To provide early feedback to developers, new Worker versions with new migrations cannot be uploaded. Read through [Gradual deployments for Durable Objects](/workers/configuration/versions-and-deployments/gradual-deployments/#gradual-deployments-for-durable-objects) for more information.
:::
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ curl -s https://example.com -H 'Cloudflare-Workers-Version-Overrides: my-worker-

## Gradual deployments for Durable Objects

Due to [global uniqueness](/durable-objects/platform/known-issues/#global-uniqueness), only one version of each [Durable Object](/durable-objects/) can run at a time. This means that gradual deployments work slightly differently for Durable Objects.
To provide [global uniqueness](/durable-objects/platform/known-issues/#global-uniqueness), only one version of each [Durable Object](/durable-objects/) can run at a time. This means that gradual deployments work slightly differently for Durable Objects.

When you create a new gradual deployment for a Durable Object Worker, each Durable Object is assigned a Worker version based on the percentages you configured in your [deployment](/workers/configuration/versions-and-deployments/#deployments). This version will not change until you create a new deployment.
When you create a new gradual deployment for a Worker with Durable Objects, each Durable Object is assigned a Worker version based on the percentages you configured in your [deployment](/workers/configuration/versions-and-deployments/#deployments). This version will not change until you create a new deployment.

![Gradual Deployments Durable Objects](~/assets/images/workers/platform/versions-and-deployments/durable-objects.png)

Expand All @@ -226,12 +226,24 @@ This is only an example, so the versions assigned to your Durable Objects may be

:::note

Typically, your Durable Object Worker will define both your Durable Object class and the Worker that interacts with it. In this case, you cannot deploy changes to your Durable Object and its Worker independently.
Typically, a Worker bundle will define both the Durable Object class and a Worker that interacts with it. In this case, you cannot deploy changes to your Durable Object and its Worker independently.

You should ensure that API changes between your Durable Object and its Worker are [forwards and backwards compatible](/durable-objects/platform/known-issues/#code-updates) whether you are using gradual deployments or not. However, using gradual deployments will make it even more likely that different versions of your Durable Objects and its Worker will interact with each other.

:::

### Migrations

Versions of Worker bundles containing new Durable Object migrations cannot be uploaded. This is because Durable Object migrations are atomic operations. Durable Object migrations can be deployed with the following command:

```sh
npx wrangler versions deploy
```

In order to limit the blast radius of Durable Object migration deployments, migrations should be deployed independently of other code changes.

To understand why Durable Object migrations are atomic operations, consider the hypothetical example of gradually deploying a delete migration. If a delete migration were applied to 50% of Durable Object instances, then Workers requesting those Durable Object instances would fail because they would have been deleted. To do this without producing errors, a version of the Worker which does not depend on any Durable Object instances would have to have already been rolled out. At which point you can deploy a delete migration without affecting any traffic and there is no reason to do so gradually.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is good explainer to have and point ppl back to 🙌


## Observability

When using gradual deployments, you may want to attribute Workers invocations to a specific version in order to get visibility into the impact of deploying new versions.
Expand Down
Loading