Skip to main content
With Always On Availability Groups, a Bytebase Instance is the group, not the server. A server hosts replicas of many groups and the primary moves on failover, so an instance registered on a server name stops working the first time its group fails over. The steps below build this mapping. For two applications on a production tier that share the same servers, the mapping looks like this: Availability group topology: each application is a project, each group is one Bytebase instance on its listener, and both groups span both servers

Scenario

Two applications, orders and billing, each with a dev group and a production group. The groups of both applications share the same servers. The groups are cut by application, which makes the project boundary obvious. If yours are cut differently, Step 1 is identical and only Step 2 changes.

Step 1 - Register one instance per group

The rest of the tutorial follows orders. Each of its groups becomes an instance with these settings: Create orders-prod:
  1. Navigate to Instances and click + New Instance. Select SQL Server.
  2. Set Name to orders-prod, Environment to Prod, and Host to orders-prod.corp with the listener’s port. Enter a login that exists on every replica; logins are server-scoped and do not fail over with the group.
  3. Under Extra Parameters, add multisubnetfailover with the value true. Skip this if the group is on a single subnet.
  4. Turn off Sync all databases under Sync Databases, then add orders and orders_audit. The listener lands on whichever server holds the primary, and that server also holds billing as a secondary of the other group. Without this limit, Bytebase syncs billing too.
  5. Click Test Connection, then Create.
The instance lists exactly two databases. Repeat for orders-dev.

Read-only connection

An instance can carry a second, read-only connection. SQL Editor queries and data exports use it instead of the admin connection. On an Availability Group with a read-only routing list, pointing this connection at the same listener with applicationintent=ReadOnly routes those reads to a readable secondary. Both connections target the listener; the admin connection lands on the primary and the read-only connection is routed to a readable secondary Add it to orders-prod:
  1. On the instance page, click + next to Connection Info.
  2. Use the same host and port, with a login that has read access.
  3. Under Extra Parameters, add applicationintent with the value ReadOnly.
  4. Save.
Bytebase does not add the parameter on its own, and results from a secondary can lag the primary. Repeat for orders-dev.

Step 2 - Create the project

  1. Click Select Project in the top bar, then New Project. Name it orders.
  2. Navigate to Databases in the workspace, select orders and orders_audit on both instances, and click Transfer to move them into the project.
The project now holds: The environments come from the instances, so a change to orders rolls to Dev first and Prod second with no further configuration. If your groups are cut by team instead of application, the project follows the team, and this is the only step that differs.

Step 3 - Verify the structure

  1. In the orders project, create a schema change on both orders databases, against any table they share. This example uses dbo.customer:
  2. The rollout shows a Dev stage and a Prod stage. Run the Dev stage, then the Prod stage.
  3. Open SQL Editor, connect to orders on orders-prod, and switch to the read-only data source. Run:
@@SERVERNAME returns the secondary, and the column is there. The change ran once, on the primary, and reached the secondary through the group’s log stream. To see why the listener matters, fail the group over. On the secondary replica, run:
The primary is now on srv-prod2. Create another change in the orders project and run the Prod stage. It succeeds without any edit to the orders-prod instance, because the listener now resolves to srv-prod2. Had the instance been registered with srv-prod1 as its host, this change would have failed: srv-prod1 is now a secondary and rejects writes.

Automate with Terraform

With many groups, registering each instance by hand does not scale. The Terraform provider creates instances from code, and its sync_databases attribute is the same Sync Databases setting from Step 1, so the inventory in the scenario table becomes the source for the configuration.

Other layouts

The mapping above assumes every database is in a group with a listener, and that a server hosts more than one group. Two common departures change only the host or the sync list:
  • Databases in no group do not fail over, so the server name is the right host. Register the server as its own instance and limit it to those databases, so the group databases on the same server stay with their listener instances.
  • One group holding every database on the server means the listener and the server name see the same databases. Register the listener anyway, since it follows the primary, and leave the sync list unset.

Summary

One principle decides the whole mapping: a Bytebase instance is an endpoint that always reaches the writable copy, limited to the databases that fail over together. With Availability Groups that endpoint is the listener and that set of databases is the group. Once the instance is right, the rest follows without further decisions: the environment is the group’s tier, the project is whatever the groups are organized by, and the read-only connection is the same listener with a read-only intent. The connection settings are documented under SQL Server Availability Groups, and the resource model under Organize Resources.