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

# Migration Best Practices

export const InternalLink = ({version, path = "", children, ...props}) => {
  let detectedVersion = version || "stable";
  if (typeof window !== 'undefined' && !version) {
    const match = window.location.pathname.match(/\/docs\/([^/]+)/);
    if (match) {
      detectedVersion = match[1];
    }
  }
  const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
  return <a href={`/docs/${detectedVersion}/${normalizedPath}`} {...props}>
      {children}
    </a>;
};

A successful migration to CockroachDB requires planning for downtime, application changes, observability, and cutover.

This page outlines key decisions, infrastructure considerations, and best practices for a resilient and repeatable high-level migration strategy:

* [Develop a migration plan](#develop-a-migration-plan).
* [Size the target CockroachDB cluster](#capacity-planning).
* Implement [application changes](#application-changes) to address necessary [schema changes](#schema-design-best-practices), [transaction contention](#handling-transaction-contention), and [unimplemented features](#unimplemented-features-and-syntax-incompatibilities).
* [Prepare for migration](#prepare-for-migration) by running a [pre-mortem](#run-a-migration-pre-mortem), setting up [metrics](#set-up-monitoring-and-alerting), [loading test data](#load-test-data), [validating application queries](#validate-queries) for correctness and performance, performing a [migration dry run](#perform-a-dry-run), and reviewing your cutover strategy.

<Tip>
  For help migrating to CockroachDB, contact our [sales team](mailto:sales@cockroachlabs.com).
</Tip>

## Develop a migration plan

Consider the following as you plan your migration:

* Who will lead and perform the migration? Which teams are involved, and which aspects are they responsible for?
* Which internal and external parties do you need to inform about the migration?
* Which external or third-party tools (e.g., microservices, analytics, payment processors, aggregators, CRMs) must be tested and migrated along with your application?
* When is the best time to perform this migration to minimize disruption to database users?
* What is your target date for completing the migration?

Create a document summarizing the migration's purpose, technical details, and team members involved.

## Capacity planning

### Cluster sizing

To size the target CockroachDB cluster, consider your data volume and workload characteristics:

* What is the total size of the data you will migrate?
* How many active <InternalLink version="stable" path="recommended-production-settings#connection-pooling">application connections</InternalLink> will be running in the CockroachDB environment?

Use this information to size the CockroachDB cluster you will create. If you are migrating to a CockroachDB Cloud cluster, see <InternalLink version="cockroachcloud" path="plan-your-cluster">Plan Your Cluster</InternalLink> for details:

* For CockroachDB Standard and Basic, your cluster will scale automatically to meet your storage and usage requirements. Refer to the <InternalLink version="cockroachcloud" path="plan-your-cluster-basic#request-units">CockroachDB Standard</InternalLink> and <InternalLink version="cockroachcloud" path="plan-your-cluster-basic#request-units">CockroachDB Basic</InternalLink> documentation to learn about how to limit your resource consumption.
* For CockroachDB Advanced, refer to the <InternalLink version="cockroachcloud" path="plan-your-cluster-advanced#example">example</InternalLink> that shows how your data volume, storage requirements, and replication factor affect the recommended node size (number of vCPUs per node) and total number of nodes on the cluster.
* For guidance on sizing for connection pools, see the CockroachDB Cloud <InternalLink version="cockroachcloud" path="production-checklist#sql-connection-handling">Production Checklist</InternalLink>.

If you are migrating to a CockroachDB self-hosted cluster:

* Refer to our <InternalLink version="stable" path="recommended-production-settings#sizing">sizing methodology</InternalLink> to determine the total number of vCPUs on the cluster and the number of vCPUs per node (which determines the number of nodes on the cluster).
* Refer to our <InternalLink version="stable" path="recommended-production-settings#storage">storage recommendations</InternalLink> to determine the amount of storage to provision on each node.
* For guidance on sizing for connection pools, see the CockroachDB self-hosted <InternalLink version="stable" path="recommended-production-settings#connection-pooling">Production Checklist</InternalLink>.

### Memory allocation

MOLT Fetch buffers data in memory regardless of the <InternalLink path="molt-fetch#define-intermediate-storage">data path</InternalLink> used. For memory sizing requirements, refer to <InternalLink path="molt-fetch-best-practices#memory-requirements">Memory requirements</InternalLink>.

## Application changes

As you develop your migration plan, consider the application changes that you will need to make. These may include the following changes:

* [Handling transaction contention.](#handling-transaction-contention)
* [Unimplemented features and syntax incompatibilities.](#unimplemented-features-and-syntax-incompatibilities)

### Schema design best practices

Convert the source table definitions into CockroachDB-compatible equivalents. CockroachDB supports the PostgreSQL wire protocol and is largely <InternalLink version="stable" path="postgresql-compatibility#features-that-differ-from-postgresql">compatible with PostgreSQL syntax</InternalLink>.

* The source and target table definitions must **match**. Review <InternalLink path="molt-fetch#type-mapping">Type mapping</InternalLink> to understand which source types can be mapped to CockroachDB types.

  For example, a PostgreSQL source table defined as `CREATE TABLE migration_schema.tbl (pk INT PRIMARY KEY);` must have a corresponding schema and table in CockroachDB:

  ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
  CREATE SCHEMA migration_schema;
  CREATE TABLE migration_schema.tbl (pk INT PRIMARY KEY);
  ```

  MySQL tables belong directly to the database specified in the connection string. A MySQL source table defined as `CREATE TABLE tbl (id INT PRIMARY KEY);` should map to CockroachDB's default `public` schema:

  ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
  CREATE TABLE tbl (id INT PRIMARY KEY);
  ```

  For example, an Oracle source table defined as `CREATE TABLE migration_schema.tbl (pk INT PRIMARY KEY);` must have a corresponding schema and table in CockroachDB:

  ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
  CREATE SCHEMA migration_schema;
  CREATE TABLE migration_schema.tbl (pk INT PRIMARY KEY);
  ```

  * MOLT Fetch can automatically define matching CockroachDB tables using the <InternalLink path="molt-fetch#handle-target-tables">`drop-on-target-and-recreate`</InternalLink> option.

  * If you define the target tables manually, review how MOLT Fetch handles <InternalLink path="molt-fetch#mismatch-handling">type mismatches</InternalLink>. You can use the <InternalLink version="cockroachcloud" path="migrations-page">MOLT Schema Conversion Tool</InternalLink> to create matching table definitions.

  * By default, table and column names are case-insensitive in MOLT Fetch. If using the <InternalLink path="molt-fetch-commands-and-flags#global-flags">`--case-sensitive`</InternalLink> flag, schema, table, and column names must match Oracle's default uppercase identifiers. Use quoted names on the target to preserve case. For example, the following CockroachDB SQL statement will error:

    ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
    CREATE TABLE co.stores (... store_id ...);
    ```

    It should be written as:

    ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
    CREATE TABLE "CO"."STORES" (... "STORE_ID" ...);
    ```

    When using `--case-sensitive`, quote all identifiers and match the case exactly (for example, use `"CO"."STORES"` and `"STORE_ID"`).

* Every table **must** have an explicit primary key.

  <Danger>
    Avoid using sequential keys. To learn more about the performance issues that can result from their use, refer to the <InternalLink version="stable" path="sql-faqs#how-do-i-generate-unique-slowly-increasing-sequential-numbers-in-cockroachdb">guidance on indexing with sequential keys</InternalLink>. If a sequential key is necessary in your CockroachDB table, you must create it manually, after using <InternalLink path="molt-fetch">MOLT Fetch</InternalLink> to load and replicate the data.
  </Danger>

* Review <InternalLink path="molt-fetch#define-transformations">Transformations</InternalLink> to understand how computed columns and partitioned tables can be mapped to the target, and how target tables can be renamed.

* By default on CockroachDB, `INT` is an alias for `INT8`, which creates 64-bit signed integers. PostgreSQL and MySQL default to 32-bit integers. Depending on your source database or application requirements, you may need to change the integer size to `4`. For more information, refer to <InternalLink version="stable" path="int#considerations-for-64-bit-signed-integers">Considerations for 64-bit signed integers</InternalLink>.

### Handling transaction contention

Optimize your queries against <InternalLink version="stable" path="performance-best-practices-overview#transaction-contention">transaction contention</InternalLink>. You may encounter <InternalLink version="stable" path="transaction-retry-error-reference">transaction retry errors</InternalLink> when you [test application queries](#validate-queries), as well as transaction contention due to long-running transactions when you <InternalLink path="migration-overview">conduct the migration</InternalLink> and bulk load data.

Transaction retry errors are more frequent under CockroachDB's default <InternalLink version="stable" path="demo-serializable">`SERIALIZABLE` isolation level</InternalLink>. If you are migrating an application that was built at a `READ COMMITTED` isolation level, you should first <InternalLink version="stable" path="read-committed#enable-read-committed-isolation">enable `READ COMMITTED` isolation</InternalLink> on the CockroachDB cluster for compatibility.

### Unimplemented features and syntax incompatibilities

Update your queries to resolve differences in functionality and SQL syntax.

CockroachDB supports the [PostgreSQL wire protocol](https://www.postgresql.org/docs/current/protocol.html) and is largely <InternalLink version="stable" path="postgresql-compatibility">compatible with PostgreSQL syntax</InternalLink>.

For full compatibility with CockroachDB, you may need to implement workarounds in your schema design, <InternalLink version="stable" path="sql-statements#data-manipulation-statements">data manipulation language (DML)</InternalLink>, or application code.

For more details on the CockroachDB SQL implementation, refer to <InternalLink version="stable" path="sql-feature-support">SQL Feature Support</InternalLink>.

## Prepare for migration

Once you have a migration plan, prepare the team, application, source database, and CockroachDB cluster for the migration.

### Run a migration "pre-mortem"

To minimize issues after cutover, compose a migration "pre-mortem":

1. Clearly describe the roles and processes of each team member performing the migration.
2. List the likely failure points and issues that you may encounter as you <InternalLink path="migration-overview">conduct the migration</InternalLink>.
3. Rank potential issues by severity, and identify ways to reduce risk.
4. Create a plan for implementing the actions that would most effectively reduce risk.

### Set up monitoring and alerting

Based on the error budget you [defined in your migration plan](#develop-a-migration-plan), identify the metrics that you can use to measure your success criteria and set up monitoring for the migration. These metrics may match those used in production or be specific to your migration goals.

### Load test data

It's useful to load test data into CockroachDB so that you can [test your application queries](#validate-queries).

MOLT Fetch <InternalLink path="molt-fetch#import-into-vs-copy-from">supports both `IMPORT INTO` and `COPY FROM`</InternalLink> for loading data into CockroachDB:

* Use `IMPORT INTO` for maximum throughput when the target tables can be offline. For a bulk data migration, most users should use `IMPORT INTO` because the tables will be offline anyway, and `IMPORT INTO` can <InternalLink version="stable" path="import-performance-best-practices">perform the data import much faster</InternalLink> than `COPY FROM`.
* Use `COPY FROM` (or `--direct-copy`) when the target must remain queryable during load.

### Validate queries

After you [load the test data](#load-test-data), validate your queries on CockroachDB by [shadowing](#shadowing) or [manually testing](#test-query-results-and-performance) them.

Note that CockroachDB defaults to the <InternalLink version="stable" path="demo-serializable">`SERIALIZABLE`</InternalLink> transaction isolation level. If you are migrating an application that was built at a `READ COMMITTED` isolation level on the source database, you must <InternalLink version="stable" path="read-committed#enable-read-committed-isolation">enable `READ COMMITTED` isolation</InternalLink> on the CockroachDB cluster for compatibility.

#### Shadowing

You can "shadow" your production workload by executing your source SQL statements on CockroachDB in parallel. You can then [validate the queries](#test-query-results-and-performance) on CockroachDB for consistency, performance, and potential issues with the migration.

#### Test query results and performance

You can manually validate your queries by testing a subset of "critical queries" on an otherwise idle CockroachDB cluster:

* Check the application logs for error messages and the API response time. If application requests are slower than expected, use the **SQL Activity** page on the <InternalLink version="cockroachcloud" path="statements-page">CockroachDB Cloud Console</InternalLink> or <InternalLink version="stable" path="ui-statements-page">DB Console</InternalLink> to find the longest-running queries that are part of that application request. If necessary, tune the queries according to our best practices for <InternalLink version="stable" path="performance-best-practices-overview">SQL performance</InternalLink>.

* Compare the results of the queries and check that they are identical in both the source database and CockroachDB.

Test performance on a CockroachDB cluster that is appropriately [sized](#capacity-planning) for your workload:

1. Run the application with single- or very low-concurrency and verify the app's performance is acceptable. The cluster should be provisioned with more than enough resources to handle this workload, because you need to verify that the queries will be fast enough when there are zero resource bottlenecks.

2. Run stress tests at or above production concurrency and rate to verify the system can handle unexpected load spikes. This can also reveal <InternalLink version="stable" path="performance-best-practices-overview#transaction-contention">contention</InternalLink> issues that may arise during peak usage and require [application design changes](#handling-transaction-contention).

### Perform a dry run

To further minimize potential surprises when you conduct the migration, practice cutover using your application and similar volumes of data on a "dry-run" environment. Use a test or development environment that is as similar as possible to production.

Performing a dry run is highly recommended. In addition to demonstrating how long the migration may take, a dry run also helps to ensure that team members understand what they need to do during the migration, and that changes to the application are coordinated.

## See also

* <InternalLink path="migration-overview">Migration Overview</InternalLink>
* <InternalLink version="stable" path="schema-design-overview">Schema Design Overview</InternalLink>
* <InternalLink version="stable" path="schema-design-indexes#best-practices">Secondary index best practices</InternalLink>
* <InternalLink version="stable" path="performance-best-practices-overview#transaction-contention">Transaction contention best practices</InternalLink>
