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

# Scale to Multiple Regions

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>;
};

This page provides guidance for scaling a single-region application to multiple regions.

Before reading this page, review <InternalLink path="multiregion-overview">Multi-Region Capabilities Overview</InternalLink>.

## Overview

Scaling an application from a single region to multiple regions consists of:

* [Scaling the database](#scale-the-database), which includes adding new nodes to a CockroachDB cluster in different regions, adding regions to the database schema, and optionally transforming the database schema to leverage multi-region table localities.
* [Scaling the application](#scale-the-application), which includes deploying the application in new regions and, if necessary, updating the application code to work with the multi-region database schema.

## Scale the database

### Step 1. Prep the database

Use an <InternalLink path="alter-database#set-primary-region">`ALTER DATABASE... SET PRIMARY REGION`</InternalLink> statement to set the database's <InternalLink path="multiregion-overview#database-regions">primary region</InternalLink> to a region in which the cluster is deployed. This region must have been specified as a <InternalLink path="cockroach-start#locality">regional locality</InternalLink> at cluster startup.

Setting the primary region before adding new regional nodes to the cluster prevents CockroachDB from <InternalLink path="architecture/replication-layer#leaseholder-rebalancing">rebalancing row replications</InternalLink> across all regions each time a node is added in a new region.

<Note>
  Executing `ALTER` statements performs a <InternalLink path="online-schema-changes">schema migration</InternalLink> on the cluster. If you are using a schema migration tool, you will need to execute these statements as raw SQL, as the <InternalLink path="multiregion-overview">multi-region SQL syntax</InternalLink> is specific to CockroachDB.

  Here are some simple tutorials on executing schema migrations against CockroachDB clusters:

  * <InternalLink path="liquibase">Migrate CockroachDB Schemas with Liquibase</InternalLink>
  * <InternalLink path="flyway">Migrate CockroachDB Schemas with Flyway</InternalLink>
  * <InternalLink path="alembic">Migrate CockroachDB Schemas with Alembic</InternalLink>
  * <InternalLink path="cockroach-sql#execute-sql-statements-from-a-file">Execute SQL statements from a file</InternalLink> and <InternalLink path="schema-design-update">Change and Remove Objects in a Database Schema</InternalLink>

  ### Step 2. Scale the cluster deployment
</Note>

Scale the cluster by adding nodes to the cluster in new regions.

For instructions on adding nodes to an existing cluster, see one of the following pages:

* For managed CockroachDB Cloud deployments, see <InternalLink version="cockroachcloud" path="cluster-management">Cluster Management</InternalLink>.
* For orchestrated deployments, see <InternalLink path="orchestrate-cockroachdb-with-kubernetes-multi-cluster">Orchestrate CockroachDB Across Multiple Kubernetes Clusters</InternalLink>.
* For manual deployments, see <InternalLink path="cockroach-start">`cockroach start`</InternalLink> and <InternalLink path="manual-deployment">Manual Deployment</InternalLink>.

<Note>
  For orchestrated and manual deployments, you must specify a <InternalLink path="cockroach-start#locality">regional locality</InternalLink> for each node at startup. These regional localities are represented as <InternalLink path="multiregion-overview#cluster-regions">cluster regions</InternalLink> in the cluster.
</Note>

### Step 3. Scale the database schema

Use an <InternalLink path="alter-database#add-region">`ALTER DATABASE... ADD REGIONS`</InternalLink> statement to add the new regions to your database. Only cluster regions (i.e., regional localities specified at cluster startup) can be added as <InternalLink path="multiregion-overview#database-regions">database regions</InternalLink>.

After you add new regions to the database schema, you can optionally configure the <InternalLink path="multiregion-overview#survival-goals">survival goals</InternalLink> and <InternalLink path="multiregion-overview">table localities</InternalLink> of the multi-region database:

* Add <InternalLink path="alter-database">`ALTER DATABASE... SURVIVE... FAILURE`</InternalLink> statements to set your database's <InternalLink path="multiregion-overview#survival-goals">survival goals</InternalLink>.
* Add <InternalLink path="alter-table#set-locality">`ALTER TABLE... SET LOCALITY`</InternalLink> statements to set <InternalLink path="multiregion-overview">table localities</InternalLink> for each table.

## Scale the application

### Step 1. Scale application deployments

Scaling application deployments in multiple regions can greatly improve latency for the end-user of the application.

For guidance on connecting to CockroachDB from an application deployment, see one of the following pages:

* For connecting to managed, CockroachDB Cloud deployments, see <InternalLink version="cockroachcloud" path="connect-to-your-cluster">Connect to a CockroachDB Standard Cluster</InternalLink> and <InternalLink version="cockroachcloud" path="connect-to-an-advanced-cluster">Connect to a CockroachDB Advanced Cluster</InternalLink>.
* For connecting to other CockroachDB deployments, see <InternalLink path="cockroach-sql">`cockroach sql`</InternalLink> and <InternalLink path="connect-to-the-database">Connect to a CockroachDB Cluster</InternalLink>.

To limit the latency between the application and the database, each deployment of the application should communicate with the closest database deployment. For details on configuring database connections for individual application deployments, consult your cloud provider's documentation. For an example using Google Cloud services, see <InternalLink path="movr-flask-deployment">Deploy a Global, Serverless Application</InternalLink>.

<Note>
  A multi-region application deployment does not require a multi-region database deployment. Deploying a global application in multiple regions can yield significant latency benefits for the end user, even if you have not yet scaled your database in multiple regions. For an example, see [Reducing Multi-Region Latency with Follower Reads](https://www.cockroachlabs.com/blog/follower-reads#:%7E:text=Deployment%202%3A%20Global%20Application%20Deployment%2C%20No%20Follower%20reads).

  If you do scale the application first, make sure that you reconfigure each application deployment to communicate with the closest database deployment after deploying the database in multiple regions.
</Note>

### Step 2. *(Optional)* Update the application code for multi-region

For most table localities, including the default locality `LOCALITY REGIONAL BY TABLE IN PRIMARY REGION`, *you do not need to update your application code after migrating your database schema for multi-region*. CockroachDB automatically optimizes queries against multi-region databases, based on the regional locality of the node executing the query, and on the multi-region configuration of the database. For more details, see <InternalLink path="regional-tables#regional-by-row-tables">Regional Tables</InternalLink>. For an extended example, see <InternalLink path="movr-flask-database">Develop and Deploy a Global Application: Create a Multi-Region Database Schema</InternalLink>.

However, there are some scenarios in which you might need to update the SQL operations in your application. For example:

* If a table has a `REGIONAL BY ROW AS <custom_region_column>` table locality, and you want to explicitly insert regional values into a table, as shown in <InternalLink path="demo-low-latency-multi-region-deployment#configure-regional-by-row-tables">Low Latency Reads and Writes in a Multi-Region Cluster</InternalLink>.
* If a table has a `REGIONAL BY ROW` locality, and you want to update the `crdb_region` value of existing rows in the table based on some other column value, as shown in <InternalLink path="alter-table#set-the-table-locality-to-regional-by-row">Set the table locality to `REGIONAL BY ROW`</InternalLink>.
* If a table has a `REGIONAL BY ROW` locality, and you want to filter a <InternalLink path="select-clause#filter-rows">selection query</InternalLink> based on the `crdb_region` value.

In all of these scenarios, statements reference the column that tracks the region for each row in a `REGIONAL BY ROW` locality. This column can be a custom column of the built-in `ENUM` type `crdb_internal_region`, or it can be the default, hidden <InternalLink path="alter-table">`crdb_region` column</InternalLink>.

If you need to explicitly reference the region-tracking column in a SQL operation in your application code, you should do the following:

* Verify that the region-tracking column is visible to the ORM.

  To make a hidden column visible, use an <InternalLink path="alter-table#alter-column">`ALTER TABLE... ALTER COLUMN... SET VISIBLE` statement</InternalLink>. By default, the `crdb_region` column created by CockroachDB is hidden.
* Using your ORM framework, sync the mapping objects in your application to reflect the latest database schema with the region-tracking column(s).
* Reference the region-tracking column in read/write operations as needed.

For example, suppose that you have a single-region table called `users` that has just been transformed into a multi-region table with a `REGIONAL BY ROW` locality. When the application was first deployed, this table had no region-tracking column. During the multi-region database schema transformation, CockroachDB automatically created a hidden `crdb_region` column to track the region of each row.

In the absence of an explicit, back-filling computed column for the hidden `crdb_region` column, there is no way for CockroachDB to determine the region for old rows of data. The following steps update the `crdb_region` values in rows that were inserted before the multi-region transformation, based on the values of a `city` column:

1. Make `crdb_region` visible in the relevant `REGIONAL BY ROW` table(s):

   ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   ALTER TABLE users ALTER COLUMN crdb_region SET VISIBLE;
   ```
2. Update the table mappings in the application code (written in Python, with [SQLAlchemy](https://www.sqlalchemy.org/)):

   ```python theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   from models import Base

   ...

   Base.metadata.reflect(bind=self.engine, extend_existing=True, autoload_replace=True)
   ```

<Note>
  SQLAlchemy allows you to update all table mappings to reflect the database with the `sqlalchemy.schema.MetaData` class method [`reflect()`](https://docs.sqlalchemy.org/core/metadata#sqlalchemy.schema.MetaData.reflect). If your ORM framework does not support updating mapping objects dynamically, you might need to add the column to the table-mapping class definition as a `String`-typed column and reinstantiate the object.
</Note>

3. Reference the column value as needed.

   Here is an example function that updates the region value in a given table, using the values of the `city` column:

   ```python theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   from sqlalchemy_cockroachdb import run_transaction
   ...

   def update_region(engine, table, region, cities):

       def update_region_helper(session, table, region, cities):
           query = table.update().where(column('city').in_(cities)).values({'crdb_region': region})
           session.execute(query)

       run_transaction(sessionmaker(bind=engine),
                       lambda session: update_region_helper(session, table, region, cities))
   ```

## See also

* <InternalLink path="multiregion-overview">Multi-Region Capabilities Overview</InternalLink>
* <InternalLink path="demo-low-latency-multi-region-deployment">Low Latency Reads and Writes in a Multi-Region Cluster</InternalLink>
