> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrations

<View title="Developer" />

<View title="Federal docs">
  > [!CAUTION]
  >
  > **Migration flags are not available in federal environments**
  >
  > To learn more, read [LaunchDarkly in federal environments](/docs/home/infrastructure/federal).
</View>

<View title="EU docs">
  > [!CAUTION]
  >
  > **Migration flags are not available in LaunchDarkly's European Union (EU) instance**
  >
  > To learn more, read [LaunchDarkly in the European Union (EU)](/docs/home/infrastructure/eu.md).
</View>

This topic explains how to use LaunchDarkly SDKs to manage migrations or modernizations. You might use this feature if you are optimizing queries, upgrading to new tech stacks, migrating from one database to another, or other similar technology changes. This feature is available for server-side and edge SDKs only.

## Prerequisites

Before you configure your SDK to manage a migration, you must complete the following prerequisites:

* Create a migration feature flag. This is a temporary flag used to migrate data or systems while keeping your application available and disruption free. Migration flags break up the switch from an old to a new implementation into a series of recommended stages where movement from one stage to the next is done in incremental steps.
* Determine how many stages your migration will have. You can select from the following options as part of creating a migration feature flag:
  * Two stages: For migrations where you cannot run the new system and old system at the same time
  * Four stages: For migrations that can run both the new and old systems at the same time
  * Six stages: For migrations where you need to migrate `READS` and `WRITES` separately

To learn more, read [Migration flags](/docs/home/flags/migration).

## Use SDKs to manage a migration

Depending on how you created your migration feature flag, your migration will have two, four, or six stages. At each stage, you will be reading data from the old destination, the new destination, or both. You will also be writing data to the old destination, the new destination, or both. At each stage, only one of these destinations is considered the authoritative source. In the LaunchDarkly SDK, you can determine which stage of the migration your application is currently in, execute the appropriate read and write methods, and then compare the results to check correctness and view any errors or changes in latency.

The following table describes the stages and which destination is authoritative. Remember that not all migrations will use all stages.

<table>
  <thead>
    <tr>
      <th>Stage</th>
      <th>Read from</th>
      <th>Write to</th>
      <th>Authoritative</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>off</td>
      <td>old</td>
      <td>old</td>
      <td>old</td>
    </tr>

    <tr>
      <td>dualwrite</td>
      <td>old</td>
      <td>old, new</td>
      <td>old</td>
    </tr>

    <tr>
      <td>shadow</td>
      <td>both</td>
      <td>old, new</td>
      <td>old</td>
    </tr>

    <tr>
      <td>live</td>
      <td>both</td>
      <td>new, old</td>
      <td>new</td>
    </tr>

    <tr>
      <td>rampdown</td>
      <td>new</td>
      <td>new, old</td>
      <td>new</td>
    </tr>

    <tr>
      <td>complete</td>
      <td>new</td>
      <td>new</td>
      <td>new</td>
    </tr>
  </tbody>
</table>

To manage your migration:

1. Configure the migration. In your SDK configuration, define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md).
2. Call the read and write methods you defined, using the SDK's migrator. The migrator determines the migration stage of the feature flag controlling the migration, and performs reads and writes to the old and new systems based on the migration stage.

For details of how to perform each step, read [Server-side SDKs](#server-side-sdks) or [Edge SDKs](#edge-sdks), below.

During the migration, you can check the consistency, errors, and latency as you manage your migration. This information is available from the flag's **Targeting** tab. To learn more, read [Migration flags](/docs/home/flags/migration).

### Customize your migration

Customizing your migration is rare. If you have additional metrics that you want to track, or if your migration or modernization involves reading and writing from the new and old systems in a different configuration than the two, four, or six -stage migrations provided, you can also use the SDK to customize your migration.

Here's how:

1. Configure the migration. In your SDK configuration, define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md).
2. Use the `migrationVariation` method to evaluate your feature flag and determine the migration stage.
3. Use your own logic to perform the appropriate migration operations for the stage. Record any metrics that you are interested in.
4. When the migration operation is complete, call the `trackMigration` method to record your metrics.

For details of how to perform each step, read [Server-side SDKs](#server-side-sdks) or [Edge SDKs](#edge-sdks), below.

## Server-side SDKs

This feature is available in the following server-side SDKs:

* [.NET (server-side)](#net-server-side)
* [Go](#go)
* [Java](#java)
* [Node.js (server-side)](#node-js-server-side)
* [PHP](#php)
* [Python](#python)
* [Ruby](#ruby)
* [Rust](#rust)

### .NET (server-side)

> **Expand .NET (server-side) code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#net-server-side).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call `Read` or `Write`. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```csharp title=".NET SDK v8.0 (C#)" lines wrap theme={null}
> Context context = Context.Builder("example-context-key")
>     .Build();
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> var defaultStage = MigrationStage.Off;
>
> var readResult = migration.Read("example-migration-flag-key", context, defaultStage, payload);
>
> var writeResult = migration.Write("example-migration-flag-key", context, defaultStage, payload);
> ```
>
> To learn more, read [`Read`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Migrations.IMigration-4.html#LaunchDarkly_Sdk_Server_Migrations_IMigration_4_Read_System_String_LaunchDarkly_Sdk_Context_LaunchDarkly_Sdk_Server_Migrations_MigrationStage_) and [`Write`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Migrations.IMigration-4.html#LaunchDarkly_Sdk_Server_Migrations_IMigration_4_Write_System_String_LaunchDarkly_Sdk_Context_LaunchDarkly_Sdk_Server_Migrations_MigrationStage_).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#net-server-side) as before.
> >
> > Then, use the `MigrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```csharp title=".NET SDK v8.0 (C#)" lines wrap theme={null}
> > Context context = Context.Builder("example-context-key")
> >     .Build();
> >
> > var (stage, tracker) = client.MigrationVariation("example-migration-flag-key", context, MigrationStage.Off);
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```csharp title=".NET SDK v8.0 (C#)" lines wrap theme={null}
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch (stage)
> >     {
> >         case MigrationStage.Off:
> >         case MigrationStage.DualWrite:
> >         case MigrationStage.Shadow:
> >         case MigrationStage.Live:
> >         case MigrationStage.RampDown:
> >         case MigrationStage.Complete:
> >         default:
> >             // throw an error
> >             break;
> >     }
> > ```
> >
> > Finally, when the migration operation is complete, call the `TrackMigration` method to record your metrics:
> >
> > ```csharp title=".NET SDK v8.0 (C#)" lines wrap theme={null}
> > client.TrackMigration(tracker);
> > ```
> >
> > To learn more, read [`IMigration`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Migrations.IMigration-4.html), [`MigrationVariation`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Migrations.IMigration-4.html#LaunchDarkly_Sdk_Server_Migrations_IMigration_4_Write_System_String_LaunchDarkly_Sdk_Context_LaunchDarkly_Sdk_Server_Migrations_MigrationStage_), and [`TrackMigration`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.LdClient.html#LaunchDarkly_Sdk_Server_LdClient_TrackMigration_LaunchDarkly_Sdk_Server_Migrations_MigrationOpTracker_).

### Go

> **Expand Go code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#go).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call `Read` or `Write`. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```go title="Go SDK v7.13.4+, using LDScopedClient" lines wrap theme={null}
> context := ldcontext.New("example-context-key")
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> defaultStage := ldmigration.Off
>
> // There is not an AllFlagsState method in the LDScopedClient.
> // If you are using scoped clients, pass in the scoped client's current context
> // LDScopedClient is in beta and may change without notice.
>
> readResult := migrator.Read("example-migration-flag-key", scopedClient.CurrentContext(), defaultStage, nil)
>
> writeResult := migrator.Write("example-migration-flag-key", scopedClient.CurrentContext(), defaultStage, nil)
> ```
>
> ```go title="Go SDK v7+, using LDClient" lines wrap theme={null}
> context := ldcontext.New("example-context-key")
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> defaultStage := ldmigration.Off
>
> readResult := migrator.Read("example-migration-flag-key", context, defaultStage, nil)
>
> writeResult := migrator.Write("example-migration-flag-key", context, defaultStage, nil)
> ```
>
> To learn more, read [`Read`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7#MigratorBuilder.Read) and [`Write`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7#MigratorBuilder.Write).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#go) as before.
> >
> > Then, use the `MigrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage, a tracker that you can use to build the analytics event to send back to LaunchDarkly, and an error.
> >
> > Here's how:
> >
> > ```go title="Go SDK v7.13.4+, using LDScopedClient" lines wrap theme={null}
> > context := ldcontext.New("example-context-key")
> > scopedClient := ld.NewScopedClient(client, context)
> > // LDScopedClient is in beta and may change without notice.
> >
> > stage, tracker, err := scopedClient.MigrationVariation("example-migration-flag-key", ldmigration.Off)
> > ```
> >
> > ```go title="Go SDK v7+, using LDClient" lines wrap theme={null}
> > context := ldcontext.New("example-context-key")
> > stage, tracker, err := client.MigrationVariation("example-migration-flag-key", context, ldmigration.Off)
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```go title="Go SDK v7+" lines wrap theme={null}
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch stage {
> >   case ldmigration.Off:
> >   case ldmigration.DualWrite:
> >   case ldmigration.Shadow:
> >   case ldmigration.Live:
> >   case ldmigration.RampDown:
> >   case ldmigration.Complete:
> >   default: {
> >     // throw an error
> >   }
> > }
> > ```
> >
> > Finally, when the migration operation is complete, call the `TrackMigrationOp` method to record your metrics:
> >
> > ```go title="Go SDK v7.13.4+, using LDScopedClient" lines wrap theme={null}
> > event, _ := tracker.Build();
> >
> > err := scopedClient.TrackMigrationOp(*event);
> > // LDScopedClient is in beta and may change without notice.
> > ```
> >
> > ```go title="Go SDK v7+, using LDClient" lines wrap theme={null}
> > event, _ := tracker.Build();
> >
> > err := client.TrackMigrationOp(*event);
> > ```
> >
> > To learn more, read [`Migration`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7#Migration) and [`TrackMigrationOp`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7#LDScopedClient.TrackMigrationOp).

### Java

> **Expand Java code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#java).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call `read` or `write`. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```java title="Java SDK v7.0" lines wrap theme={null}
> LDContext context = LDContext.builder("example-context-key")
>   .build();
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> MigrationStage defaultStage = MigrationStage.OFF;
>
> Migration.MigrationResult<String> readResult = migration.read("example-migration-flag-key", context, defaultStage);
>
> Migration.MigrationWriteResult<String> writeResult = migration.write("example-migration-flag-key", context, defaultStage);
> ```
>
> To learn more, read [`Migration`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/migrations/Migration.html).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#java) as before.
> >
> > Then, use the `migrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage, a tracker that you can use to build the analytics event to send back to LaunchDarkly, and an error.
> >
> > Here's how:
> >
> > ```java title="Java SDK v7.0" lines wrap theme={null}
> > LDContext context = LDContext.builder("example-context-key")
> >   .build();
> >
> > MigrationVariation migrationVariation = client.migrationVariation("example-migration-flag-key", context, MigrationStage.OFF);
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```java title="Java SDK v7.0" lines wrap theme={null}
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch (migrationVariation.getStage()) {
> >   case OFF:
> >   case DUAL_WRITE:
> >   case SHADOW:
> >   case LIVE:
> >   case RAMP_DOWN:
> >   case COMPLETE:
> >   default: {
> >     // throw an error
> >   }
> > }
> > ```
> >
> > Finally, when the migration operation is complete, call the `trackMigration` method to record your metrics:
> >
> > ```java title="Java SDK v7.0" lines wrap theme={null}
> > MigrationOpTracker tracker = migrationVariation.getTracker();
> >
> > client.trackMigration(tracker);
> > ```
> >
> > To learn more, read [`migrationVariation`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/LDClient.html#migrationVariation-java.lang.String-com.launchdarkly.sdk.LDContext-com.launchdarkly.sdk.server.MigrationStage-) and [`trackMigration`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/LDClient.html#trackMigration-com.launchdarkly.sdk.server.MigrationOpTracker-).

### Node.js (server-side)

> **Expand Node.js (server-side) code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#node-js-server-side).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call the `read` or `write` methods from the `LDMigration` interface. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```ts title="Node.js (server-side) SDK v9" maxLines=0 expandable lines wrap theme={null}
> import { LDContext, LDMigrationStage, createMigration } from '@launchdarkly/node-server-sdk';
>
> const context: LDContext = {
>    kind: 'user',
>    key: 'example-user-key',
>    name: 'Sandy',
> };
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> let defaultStage: LDMigrationStage = LDMigrationStage.Off;
>
> const migration = createMigration(client, options);
>
> // when you need to perform a read in your application
> migration.read(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
>
> // when you need to perform a write in your application
> migration.write(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
> ```
>
> To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/server-node/docs/interfaces/LDMigration.html).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#node-js-server-side) as before.
> >
> > Then, use the `migrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns a promise that is resolved with the result `LDMigrationVariation`. This result includes the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```ts title="Node.js (server-side) SDK v9" lines wrap theme={null}
> >   import { LDContext, LDMigrationStage } from '@launchdarkly/node-server-sdk';
> >
> >   const context: LDContext = {
> >      kind: 'user',
> >      key: 'example-user-key',
> >      name: 'Sandy',
> >   };
> >
> >   const { value, tracker } = await client.migrationVariation(
> >     'example-migration-flag-key',
> >     context,
> >     LDMigrationStage.Off
> >   );
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```ts title="Node.js (server-side) SDK v9" expandable lines wrap theme={null}
> > import { LDMigrationStage } from '@launchdarkly/node-server-sdk';
> >
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch (value) {
> >   case LDMigrationStage.Off: { }
> >   case LDMigrationStage.DualWrite: { }
> >   case LDMigrationStage.Shadow: { }
> >   case LDMigrationStage.Live: { }
> >   case LDMigrationStage.RampDown: { }
> >   case LDMigrationStage.Complete: { }
> >   default: {
> >     // throw an error
> >   }
> > }
> > ```
> >
> > Finally, when the migration operation is complete, call the `trackMigration` method to record your metrics:
> >
> > ```ts title="Node.js (server-side) SDK v9" lines wrap theme={null}
> > const event = tracker.createEvent();
> >
> > if (event) {
> >   client.trackMigration(event);
> > }
> > ```
> >
> > To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/server-node/docs/interfaces/LDMigration.html). and [`LDMigrationOpEvent`](https://launchdarkly.github.io/js-core/packages/sdk/server-node/docs/interfaces/LDMigrationOpEvent.html).

### PHP

> **Expand PHP code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#php).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call the `read` or `write` methods from the `Migrator` interface. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```php title="PHP SDK v6" maxLines=0 expandable lines wrap theme={null}
> $context = LaunchDarkly\LDContext::builder("example-context-key")->build();
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> $defaultStage = Migrations\Stage::OFF;
>
> $result = $builder->build();
> if (!$result->isSuccessful()) {
>     throw new \Exception($result->error);
> }
>
> $migrator = $result->value;
>
> // if you need to pass additional information from the call site
> // to your read/write methods, use a mixed type payload
> $payload = ['index' => 'useful information'];
>
> // when you need to perform a read in your application
> $migrator->read('example-migration-flag-key', $context, $defaultStage, $payload);
>
> // when you need to perform a write in your application
> $migrator->write('example-migration-flag-key', $context, $defaultStage, $payload);
> ```
>
> To learn more, read [`Migrator`](https://launchdarkly.github.io/php-server-sdk/classes/LaunchDarkly-Migrations-Migrator.html).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#php) as before.
> >
> > Then, use the `migrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```php title="PHP SDK v6" lines wrap theme={null}
> > $context = LaunchDarkly\LDContext::builder("example-context-key")->build();
> >
> > $result = $client->migrationVariation('example-migration-flag-key', $context, Migrations\Stage::OFF);
> >
> > /** @var Migrations\Stage */
> > $stage = $result['stage'];
> > /** @var Migrations\OpTracker */
> > $tracker = $result['tracker'];
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```php title="PHP SDK v6" lines wrap theme={null}
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch ($stage) {
> >   case Migrations\Stage::OFF:
> >   case Migrations\Stage::DUALWRITE:
> >   case Migrations\Stage::SHADOW:
> >   case Migrations\Stage::LIVE:
> >   case Migrations\Stage::RAMPDOWN:
> >   case Migrations\Stage::COMPLETE:
> >   default:
> >     // throw an error
> > }
> > ```
> >
> > Finally, when the migration operation is complete, call the `trackMigrationOperation` method to record your metrics:
> >
> > ```php title="PHP SDK v6" lines wrap theme={null}
> > $client->trackMigrationOperation($tracker);
> > ```
> >
> > To learn more, read [`Migrator`](https://launchdarkly.github.io/php-server-sdk/classes/LaunchDarkly-Migrations-Migrator.html) and [`trackMigrationOperation`](https://launchdarkly.github.io/php-server-sdk/classes/LaunchDarkly-LDClient.html#method_trackMigrationOperation).

### Python

> **Expand Python code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#python).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call the `read` or `write` methods from the `Migrator` interface. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```python title="Python SDK v9" expandable lines wrap theme={null}
> from ldclient import Context
> from ldclient.migrations import Stage
>
> context = Context.builder("example-context-key").build()
>
>
> # this is the migration stage to use if the flag's migration stage
> # is not available from LaunchDarkly
> default_stage = Stage.OFF
>
> migrator = builder.build()
>
> # when you need to perform a read in your application
> migrator.read(
>     'example-migration-flag-key',
>     context,
>     default_stage
> )
>
> # when you need to perform a write in your application
> migrator.write(
>     'example-migration-flag-key',
>     context,
>     default_stage
> )
> ```
>
> To learn more, read [`ldclient.migrations`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#module-ldclient.migrations).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#python) as before.
> >
> > Then, use the `migration_variation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```python title="Python SDK v9" lines wrap theme={null}
> > context = Context.builder("example-context-key").build()
> >
> > stage, tracker = ldclient.get().migration_variation('example-migration-flag-key', context, Stage.OFF)
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```python title="Python SDK v9" expandable lines wrap theme={null}
> > # define the combination of reads and writes from the new and old systems
> > # that should occur at each migration stage
> >
> > if stage == Stage.OFF:
> >   pass
> > elif stage == Stage.DUALWRITE:
> >   pass
> > elif stage == Stage.SHADOW:
> >   pass
> > elif stage == Stage.LIVE:
> >   pass
> > elif stage == Stage.RAMPDOWN:
> >   pass
> > elif stage == Stage.COMPLETE:
> >   pass
> > else:
> >   # throw an error
> >   pass
> > ```
> >
> > Finally, when the migration operation is complete, call the `track_migration_op` method to record your metrics:
> >
> > ```python title="Python SDK v9" lines wrap theme={null}
> > ldclient.get().track_migration_op(tracker)
> > ```
> >
> > To learn more, read [`ldclient.migrations`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#module-ldclient.migrations) and [`track_migration_op`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-main.html#ldclient.client.LDClient.track_migration_op).

### Ruby

> **Expand Ruby code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#ruby).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call `read` or `write`. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```ruby title="Ruby SDK v8.0" lines wrap theme={null}
> context = LaunchDarkly::LDContext.create({key: "example-user-key", kind:"user"})
>
> # this is the migration stage to use if the flag's migration stage
> # is not available from LaunchDarkly
> default_stage = LaunchDarkly::Migrations::STAGE_OFF
>
> read_result = migrator.read("example-migration-flag-key", context, default_stage, payload)
>
> write_result = migrator.write("example-migration-flag-key", context, default_stage, payload)
> ```
>
> To learn more, read [`read`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/Migrations/Migrator.html#read-instance_method) and [`write`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/Migrations/Migrator.html#write-instance_method).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#ruby) as before.
> >
> > Then, use the `migration_variation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```ruby title="Ruby SDK v8.0" lines wrap theme={null}
> > context = LaunchDarkly::LDContext.create({key: "example-user-key", kind:"user"})
> >
> > stage, tracker = client.migration_variation(
> >   "example-migration-flag-key",
> >   context,
> >   LaunchDarkly::Migrations::STAGE_OFF
> > )
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```ruby title="Ruby SDK v8.0" lines wrap theme={null}
> > # define the combination of reads and writes from the new and old systems
> > # that should occur at each migration stage
> >
> > case stage
> > when LaunchDarkly::Migrations::STAGE_OFF
> > when LaunchDarkly::Migrations::STAGE_DUALWRITE
> > when LaunchDarkly::Migrations::STAGE_SHADOW
> > when LaunchDarkly::Migrations::STAGE_LIVE
> > when LaunchDarkly::Migrations::STAGE_RAMPDOWN
> > when LaunchDarkly::Migrations::STAGE_COMPLETE
> > else
> >   # throw an error
> > end
> > ```
> >
> > Finally, when the migration operation is complete, call the `track_migration_op` method to record your metrics:
> >
> > ```ruby title="Ruby SDK v8.0" lines wrap theme={null}
> > client.track_migration_op(tracker);
> > ```
> >
> > To learn more, read [`Migrator`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/Migrations/Migrator.html) and [`track_migration_op`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/LDClient.html#track_migration_op-instance_method).

### Rust

> **Expand Rust code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#rust).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call `read` or `write`. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```rust title="Rust SDK v2.2" expandable lines wrap theme={null}
> let context = ContextBuilder::new("example-user-key")
>     .kind("user")
>     .build()
>     .expect("Context failed to build");
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> let default_stage = Stage::Off;
>
> let read_result = migrator
>     .read(
>         &context,
>         "example-migration-flag-key".into(),
>         default_stage,
>         "example-payload".into(),
>     )
>     .await;
>
> let write_result = migrator
>     .write(
>         &context,
>         "example-migration-flag-key".into(),
>         default_stage,
>         "example-payload".into(),
>     )
>     .await;
> ```
>
> To learn more, read [`read`](https://docs.rs/launchdarkly-server-sdk/latest/launchdarkly_server_sdk/struct.Migrator.html#method.read) and [`write`](https://docs.rs/launchdarkly-server-sdk/latest/launchdarkly_server_sdk/struct.Migrator.html#method.write).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#rust) as before.
> >
> > Then, use the `migration_variation` method to evaluate your feature flag and determine its migration stage. This method returns the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```rust title="Rust SDK v2.2" lines wrap theme={null}
> > let context = ContextBuilder::new("example-user-key")
> >     .kind("user")
> >     .build()
> >     .expect("Context failed to build");
> >
> > let (stage, tracker) =
> >     client.migration_variation(&context, "example-migration-flag-key", Stage::Off);
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```rust title="Rust SDK v2.2" lines wrap theme={null}
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > match stage {
> >     Stage::Off => todo!(),
> >     Stage::DualWrite => todo!(),
> >     Stage::Live => todo!(),
> >     Stage::Shadow => todo!(),
> >     Stage::Rampdown => todo!(),
> >     Stage::Complete => todo!(),
> >     _ => todo!(),
> > };
> > ```
> >
> > Finally, when the migration operation is complete, call the `track_migration_op` method to record your metrics:
> >
> > ```rust title="Rust SDK v2.2" lines wrap theme={null}
> > client.track_migration_op(tracker);
> > ```
> >
> > To learn more, read [`Migrator`](https://docs.rs/launchdarkly-server-sdk/latest/launchdarkly_server_sdk/struct.Migrator.html) and [`track_migration_op`](https://docs.rs/launchdarkly-server-sdk/latest/launchdarkly_server_sdk/struct.Client.html#method.track_migration_op).

## Edge SDKs

This feature is available in the following edge SDKs:

* [Akamai](#akamai)
* [Cloudflare](#cloudflare)
* [Vercel](#vercel)

### Akamai

> **Expand Akamai code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#akamai).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call the `read` or `write` methods from the `LDMigration` interface. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```ts title="Akamai SDK v1.0.9+" expandable lines wrap theme={null}
> import {
>   createMigration,
>   LDContext,
>   LDMigrationStage,
> } from '@launchdarkly/akamai-server-edgekv-sdk';
>
> const context: LDContext = {
>    kind: 'user',
>    key: 'example-user-key',
>    name: 'Sandy',
> };
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> let defaultStage: LDMigrationStage = LDMigrationStage.Off;
>
> const migration = createMigration(client, options);
>
> // when you need to perform a read in your application
> migration.read(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
>
> // when you need to perform a write in your application
> migration.write(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
> ```
>
> To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/akamai-edgekv/docs/interfaces/LDMigration.html).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#akamai) as before.
> >
> > Then, use the `migrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns a promise that is resolved with the result `LDMigrationVariation`. This result includes the migration stage. It also returns a tracker, which you can ignore. (The tracker is normally used to build an analytics event to send back to LaunchDarkly. However, the Akamai SDK does not support sending events, so there is no need to build one.)
> >
> > Here's how:
> >
> > ```ts title="Akamai SDK v1.0.9+" expandable lines wrap theme={null}
> >   import {
> >     LDContext,
> >     LDMigrationStage,
> >   } from '@launchdarkly/akamai-server-edgekv-sdk';
> >
> >   const context: LDContext = {
> >      kind: 'user',
> >      key: 'example-user-key',
> >      name: 'Sandy',
> >   };
> >
> >   const { value, tracker } = await client.migrationVariation(
> >     'example-migration-flag-key',
> >     context,
> >     LDMigrationStage.Off
> >   );
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```ts title="Akamai SDK v1.0.9+" expandable lines wrap theme={null}
> > import { LDMigrationStage } from '@launchdarkly/akamai-server-edgekv-sdk';
> >
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch (value) {
> >   case LDMigrationStage.Off: { }
> >   case LDMigrationStage.DualWrite: { }
> >   case LDMigrationStage.Shadow: { }
> >   case LDMigrationStage.Live: { }
> >   case LDMigrationStage.RampDown: { }
> >   case LDMigrationStage.Complete: { }
> >   default: {
> >     // throw an error
> >   }
> > }
> > ```
> >
> > To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/akamai-edgekv/docs/interfaces/LDMigration.html).

### Cloudflare

> **Expand Cloudflare code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#cloudflare).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call the `read` or `write` methods from the `LDMigration` interface. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```ts title="Cloudflare SDK v2.2.2+" expandable lines wrap theme={null}
> import {
>   createMigration,
>   LDContext,
>   LDMigrationStage,
> } from '@launchdarkly/cloudflare-server-sdk';
>
> const context: LDContext = {
>    kind: 'user',
>    key: 'example-user-key',
>    name: 'Sandy',
> };
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> let defaultStage: LDMigrationStage = LDMigrationStage.Off;
>
> const migration = createMigration(client, options);
>
> // when you need to perform a read in your application
> migration.read(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
>
> // when you need to perform a write in your application
> migration.write(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
> ```
>
> To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/cloudflare/docs/interfaces/LDMigration.html).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#cloudflare) as before.
> >
> > Then, use the `migrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns a promise that is resolved with the result `LDMigrationVariation`. This result includes the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```ts title="Cloudflare SDK v2.2.2+" expandable lines wrap theme={null}
> >   import {
> >     LDContext,
> >     LDMigrationStage,
> >   } from '@launchdarkly/cloudflare-server-sdk'
> >
> >   const context: LDContext = {
> >      kind: 'user',
> >      key: 'example-user-key',
> >      name: 'Sandy',
> >   };
> >
> >   const { value, tracker } = await client.migrationVariation(
> >     'example-migration-flag-key',
> >     context,
> >     LDMigrationStage.Off
> >   );
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```ts title="Cloudflare SDK v2.2.2+" expandable lines wrap theme={null}
> > import { LDMigrationStage } from '@launchdarkly/cloudflare-server-sdk';
> >
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch (value) {
> >   case LDMigrationStage.Off: { }
> >   case LDMigrationStage.DualWrite: { }
> >   case LDMigrationStage.Shadow: { }
> >   case LDMigrationStage.Live: { }
> >   case LDMigrationStage.RampDown: { }
> >   case LDMigrationStage.Complete: { }
> >   default: {
> >     // throw an error
> >   }
> > }
> > ```
> >
> > Finally, when the migration operation is complete, call the `trackMigration` method to record your metrics:
> >
> > ```ts title="Cloudflare SDK v2.2.2+" lines wrap theme={null}
> > import {
> >   LDClient,
> >   LDMigrationTracker,
> > } from '@launchdarkly/cloudflare-server-sdk';
> >
> > const event = tracker.createEvent();
> >
> > if (event) {
> >   client.trackMigration(event);
> > }
> > ```
> >
> > To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/cloudflare/docs/interfaces/LDMigration.html) and [`LDMigrationOpEvent`](https://launchdarkly.github.io/js-core/packages/sdk/cloudflare/docs/interfaces/LDMigrationOpEvent.html).

### Vercel

> **Expand Vercel code sample**
>
> To manage your migration, first you need to define how to read from and write to the old and new systems, how to check whether two reads are a match, and whether to track errors and latency metrics. To learn more, read [Migration configuration](/docs/sdk/features/migration-config.md#vercel).
>
> Then, whenever you need to perform a read or write in the systems that you are modernizing or migrating, call the `read` or `write` methods from the `LDMigration` interface. The SDK evaluates the flag, determines which migration stage the flag is in, and performs the reads or writes in the [appropriate system](#use-sdks-to-manage-a-migration).
>
> Here's how:
>
> ```ts title="Vercel SDK v1.1.6+" expandable lines wrap theme={null}
> import {
>   createMigration,
>   LDContext,
>   LDMigrationStage,
> } from '@launchdarkly/vercel-server-sdk';
>
> const context: LDContext = {
>    kind: 'user',
>    key: 'example-user-key',
>    name: 'Sandy',
> };
>
> // this is the migration stage to use if the flag's migration stage
> // is not available from LaunchDarkly
> let defaultStage: LDMigrationStage = LDMigrationStage.Off;
>
> const migration = createMigration(client, options);
>
> // when you need to perform a read in your application
> migration.read(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
>
> // when you need to perform a write in your application
> migration.write(
>   'example-migration-flag-key',
>   context,
>   defaultStage
> );
> ```
>
> To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/vercel/docs/interfaces/LDMigration.html).
>
> You can check for consistency, errors, or latency under "Migration insights" on the **Targeting** tab of your migration flag in the LaunchDarkly user interface. To learn more, read [Migration flags](/docs/home/flags/migration).
>
> > **Expand Customizing your migration**
> >
> > #### Customizing your migration
> >
> > Customizing your migration is rare. If you want to customize your migration, [configure your migration information](/docs/sdk/features/migration-config.md#vercel) as before.
> >
> > Then, use the `migrationVariation` method to evaluate your feature flag and determine its migration stage. This method returns a promise that is resolved with the result `LDMigrationVariation`. This result includes the migration stage and a tracker that you can use to build the analytics event to send back to LaunchDarkly.
> >
> > Here's how:
> >
> > ```ts title="Vercel SDK v1.1.6+" expandable lines wrap theme={null}
> >   import {
> >     LDContext,
> >     LDMigrationStage,
> >   } from '@launchdarkly/vercel-server-sdk';
> >
> >   const context: LDContext = {
> >      kind: 'user',
> >      key: 'example-user-key',
> >      name: 'Sandy',
> >   };
> >
> >   const { value, tracker } = await client.migrationVariation(
> >     'example-migration-flag-key',
> >     context,
> >     LDMigrationStage.Off
> >   );
> > ```
> >
> > Next, perform the migration for the appropriate stage. At each stage, the migration may involve reading or writing from one or both systems. You must define the behavior for each stage. To learn more about how LaunchDarkly defines the stages, read [Use SDKs to manage a migration](#use-sdks-to-manage-a-migration), above.
> >
> > The structure looks like this:
> >
> > ```ts title="Vercel SDK v1.1.6+" expandable lines wrap theme={null}
> > import { LDMigrationStage } from '@launchdarkly/vercel-server-sdk';
> >
> > // define the combination of reads and writes from the new and old systems
> > // that should occur at each migration stage
> >
> > switch (value) {
> >   case LDMigrationStage.Off: { }
> >   case LDMigrationStage.DualWrite: { }
> >   case LDMigrationStage.Shadow: { }
> >   case LDMigrationStage.Live: { }
> >   case LDMigrationStage.RampDown: { }
> >   case LDMigrationStage.Complete: { }
> >   default: {
> >     // throw an error
> >   }
> > }
> > ```
> >
> > Finally, when the migration operation is complete, call the `trackMigration` method to record your metrics:
> >
> > ```ts title="Vercel SDK v1.1.6+" lines wrap theme={null}
> > import {
> >   LDMigrationTracker,
> >   LDClient
> > } from '@launchdarkly/vercel-server-sdk';
> >
> > const event = tracker.createEvent();
> >
> > if (event) {
> >   client.trackMigration(event);
> > }
> > ```
> >
> > To learn more, read [`LDMigration`](https://launchdarkly.github.io/js-core/packages/sdk/vercel/docs/interfaces/LDMigration.html) and [`LDMigrationOpEvent`](https://launchdarkly.github.io/js-core/packages/sdk/vercel/docs/interfaces/LDMigrationOpEvent.html).
