Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO] Update DO migration docs #19385

Open
wants to merge 9 commits into
base: production
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -3,96 +3,228 @@ pcx_content_type: concept
title: Durable Objects migrations
sidebar:
order: 2

---

import { GlossaryTooltip } from "~/components";
import { GlossaryTooltip, WranglerConfig } from "~/components";

A migration is a mapping process from a class name to a runtime state.
A migration is a mapping process from a class name to a runtime state. This process communicates the changes to the Workers runtime and provides the runtime with instructions on how to deal with those changes.

You must initiate a migration process when you:
To apply a migration, you need to:

* Create a new <GlossaryTooltip term="Durable Object class">Durable Object class</GlossaryTooltip>.
* Rename a Durable Object class.
* Delete a Durable Object class.
* Transfer an existing Durable Objects class.
1. Edit your `wrangler.json` file, as explained below.
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved
2. Re-deploy your Worker using `npx wrangler deploy`.

You must initiate a migration process when you:

This process informs the Workers runtime of the changes and provides it with instructions on how to deal with those changes.
- Create a new <GlossaryTooltip term="Durable Object class">Durable Object class</GlossaryTooltip>.
- Rename a Durable Object class.
- Delete a Durable Object class.
- Transfer an existing Durable Objects class.

:::note

Updating the code for an existing Durable Object class does not require a migration. To update the code for an existing Durable Object class, run [`npx wrangler deploy`](/workers/wrangler/commands/#deploy). This is true even for changes to how the code interacts with persistent storage. Because of [global uniqueness](/durable-objects/platform/known-issues/#global-uniqueness), you do not have to be concerned about old and new code interacting with the same storage simultaneously. However, it is your responsibility to ensure that the new code is backwards compatible with existing stored data.

:::

## Create migration

The most common migration performed is a new class migration, which informs the runtime that a new Durable Object class is being uploaded. This is also the migration you need when creating your first Durable Object class.

To apply a create migration, edit your `wrangler.json` file in the following way:

<WranglerConfig>
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved

```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>

## Delete migration

Running a delete migration will delete all Durable Objects associated with the deleted class, including all of their stored data.

- Do not run a delete migration on a class without first ensuring that you are not relying on the Durable Objects within that Worker anymore, that is, first remove the binding from the Worker.
- Copy any important data to some other location before deleting.
- You do not have to run a delete migration on a class that was renamed or transferred.

To apply a delete migration, edit your `wrangler.json` file in the following way:
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved

<WranglerConfig>

```toml
[[migrations]]
tag = "<v2>" # Migration identifier. This should be unique for each migration entry
deleted_classes = ["<ClassToDelete>"] # Array of deleted class names
```

</WranglerConfig>

Updating code for an existing Durable Object class does not require a migration. To update code for an existing Durable Object class, run [`npx wrangler deploy`](/workers/wrangler/commands/#deploy). This is true even for changes to how code interacts with persistent storage. Because of [global uniqueness](/durable-objects/platform/known-issues/#global-uniqueness), you do not have to be concerned about old and new code interacting with the same storage simultaneously. However, it is your responsibility to ensure that new code is backwards compatible with existing stored data.
## Rename migration

Rename migrations are used to transfer stored Durable Objects between two Durable Object classes in the same Worker code file.

To apply a rename migration, edit your `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

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

</WranglerConfig>

## Transfer migration

Transfer migrations are used to transfer stored Durable Objects between two Durable Object classes in different Worker code files.

If you want to transfer stored Durable Objects between two Durable Object classes in the same Worker code file, use [rename migrations](#rename-migration) instead.

:::note

Do not run a [Create migration](#create-migration) for the destination class before running a transfer migration. The Transfer migration will create the destination class for you.

:::

The most common migration performed is a new class migration, which informs the runtime that a new Durable Object class is being uploaded.
To apply a transfer migration, edit your `wrangler.json` file in the following way:

Migrations can also be used for transferring stored data between two Durable Object classes:
<WranglerConfig>

* Rename migrations are used to transfer stored Durable Objects between two Durable Object classes in the same Worker code file.
* Transfer migrations are used to transfer stored Durable Objects between two Durable Object classes in different Worker code files.
```toml
[[durable_objects.bindings]]
name = "<MY_DURABLE_OBJECT>"
class_name = "<DestinationDurableObjectClass>"

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.
[[migrations]]
tag = "<v1>" # Migration identifier. This should be unique for each migration entry
transferred_classes = [{from = "<SourceDurableObjectClass>", from_script = "<SourceWorkerScript>", to = "<DestinationDurableObjectClass>" }]
```

</WranglerConfig>

:::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.

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.toml` file for their next deployment.

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.

:::

Migrations can also be used to delete a Durable Object class and its stored Durable Objects.
## Durable Object migrations configuration in `wrangler`
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved

:::caution[Delete migrations]
- Migrations are performed through the `[[migrations]]` configurations key in your `wrangler.toml` file or `migration` key in your `wrangler.json` file.

- Migrations require a migration tag, which is defined by the `tag` property in each migration entry.

Running a delete migration will delete all Durable Objects associated with the deleted class, including all of their stored data. Do not run a delete migration on a class without first ensuring that you are not relying on the Durable Objects within that class anymore. Copy any important data to some other location before deleting.
- Migration tags are treated like unique names and are used to determine which migrations have already been applied. Once a given Worker code has a migration tag set on it, all future Worker code deployments must include a migration tag.

- The migration list is an ordered array of tables, specified as a top-level key in your `wrangler` configuration file. The migration list is inherited by all environments and cannot be overridden by a specific environment.

- All migrations are applied at deployment. Each migration can only be applied once per [environment](/durable-objects/reference/environments/).

- Each migration in the list can have multiple directives, and multiple migrations can be specified as your project grows in complexity.

:::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.

:::

### Durable Object migrations in `wrangler.toml`
## Examples of Durable Object migration

Migrations are performed through the `[[migrations]]` configurations key in your `wrangler.toml` file.
To illustrate an example migrations workflow, the `DurableObjectExample` class can be initially defined with:

Migrations require a migration tag, which is defined by the `tag` property in each migration entry.
<WranglerConfig>

Migration tags are treated like unique names and are used to determine which migrations have already been applied. Once a given Worker code has a migration tag set on it, all future Worker code deployments must include a migration tag.
```toml
# Creating a new Durable Object class
[[migrations]]
tag = "v1" # Migration identifier. This should be unique for each migration entry
new_classes = ["DurableObjectExample"] # Array of new classes
```

The migration list is an ordered array of tables, specified as a top-level key in your `wrangler.toml` file. The migration list is inherited by all environments and cannot be overridden by a specific environment.
</WranglerConfig>

All migrations are applied at deployment. Each migration can only be applied once per [environment](/durable-objects/reference/environments/).
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.

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

import { WranglerConfig } from "~/components";
To create new classes, add the following to your `wrangler` configuration file and deploy the Worker:

<WranglerConfig>

```toml
# Creating a new Durable Object class
[[durable_objects.bindings]]
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved
name = "DEPRECATED_DURABLE_OBJECT"
class_name = "DeprecatedClass"

[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "DurableObjectExample"


[[migrations]]
tag = "v1" # Should be unique for each entry
new_classes = ["DurableObjectExample"] # Array of new classes
new_classes = ["DeprecatedClass","DurableObjectExample"] # Array of new classes
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved
```

</WranglerConfig>

### Delete migration example

To run the Delete migration, first remove the binding for the `DeprecatedClass` and deploy the Worker.
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved

<WranglerConfig>

```toml
# Remove the binding for the DeprecatedClass DO
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "DurableObjectExample"


[[migrations]]
tag = "v1" # Should be unique for each entry
new_classes = ["DeprecatedClass","DurableObjectExample"] # Array of new classes
```

</WranglerConfig>

Each migration in the list can have multiple directives, and multiple migrations can be specified as your project grows in complexity. For example, you may want to rename the `DurableObjectExample` class to `UpdatedName` and delete an outdated `DeprecatedClass` entirely.
If you just want to run the Delete migration, add the Delete migration configuration and deploy the Worker.

### Rename migration example

To run Rename migration, update the binding for the `DurableObjectExample` to the new class name `UpdatedName`. Add the Rename migration configuration and deploy the Worker.

To apply both migrations in the same deploy, add the migrations configuration and deploy the Worker.

<WranglerConfig>

```toml
# Before deleting the `DeprecatedClass` remove the binding for the `DeprecatedClass`.
# Update the binding for the `DurableObjectExample` to the new class name `UpdatedName`.
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "UpdatedName"

[[migrations]]
tag = "v1" # Should be unique for each entry
new_classes = ["DurableObjectExample"] # Array of new classes
new_classes = ["DeprecatedClass","DurableObjectExample"] # Array of new classes

# Renaming and deleting classes
Oxyjun marked this conversation as resolved.
Show resolved Hide resolved
[[migrations]]
tag = "v2"
renamed_classes = [{from = "DurableObjectExample", to = "UpdatedName" }] # Array of rename directives
Expand All @@ -101,25 +233,35 @@ deleted_classes = ["DeprecatedClass"] # Array of deleted class names

</WranglerConfig>

:::note
### Transfer migration example

You can transfer stored Durable Objects from `DurableObjectExample` to `TransferredClass` from a Worker script named `OldWorkerScript`. The configuration of the `wrangler` file for your new Worker code (destination Worker code) would look like this:

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.
<WranglerConfig>

```toml
# destination worker
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "TransferredClass"

:::
# Transferring class
[[migrations]]
tag = "v1"
transferred_classes = [{from = "DurableObjectExample", from_script = "OldWorkerScript", to = "TransferredClass" }]
```

</WranglerConfig>

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

:::note[SQLite in Durable Objects Beta]

The new beta version of Durable Objects is available where each Durable Object has a private, embedded SQLite database. When deploying a new Durable Object class, users can opt-in to a SQLite storage backend in order to access new [SQL API](/durable-objects/api/sql-storage/#exec). Otherwise, a Durable Object class has a key-value storage backend.

:::

To allow a new Durable Object class to use a SQLite storage backend, use `new_sqlite_classes` on the migration in your Worker's `wrangler.toml` file:


To allow a new Durable Object class to use a SQLite storage backend, use `new_sqlite_classes` on the migration in your Worker's `wrangler` configuration file:

<WranglerConfig>

Expand All @@ -131,4 +273,6 @@ new_sqlite_classes = ["MyDurableObject"] # Array of new classes

</WranglerConfig>

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.
Loading