When you're migrating your schema, data, and metadata from a source database to a
destination database, you want to ensure that all of this information is
migrated accurately. Database Migration Service provides a high-fidelity way to
migrate database objects (including the schema, data, and metadata) from one
database to another.
All of the following data, schema, and metadata components are migrated as part
of the database migration:
Data
All tables from all databases and schemas, excluding the following schemas:
The information schema information_schema
Any schemas beginning with pg (for example, pg_catalog)
Only data manipulation language (DML) changes are updated automatically during
continuous migrations. Managing data definition language (DDL) changes so that the source and destination databases remain compatible is the
responsibility of the user, and can be achieved in two ways:
Stopping writes to the source and running the DDL commands in both source and
destination. Before running DDL commands on the destination, grant
alloydbexternalsync to the AlloyDB user applying the DDL
changes. To enable querying or changing the data, grant the
alloydbexternalsync role to the relevant AlloyDB users.
Using the pglogical.replicate_ddl_command to allow DDL to be run
on the source and destination at a consistent point. The user running this
command must have the same username on both the source and the destination,
and should be the superuser or the owner of the artifact being migrated
(for example, the table, sequence, view, or database).
Here are a few examples of using the pglogical.replicate_ddl_command.
Replace:
[SCHEMA] with the name of the table schema you want to use
[TABLE_NAME] with the table name
[NEW_NAME_FOR_TABLE] with the new name for the table when when performing the rename operation
Add a column to a database table with a primary key
Change the name of a database table with a primary key
selectpglogical.replicate_ddl_command('ALTER TABLE [SCHEMA].[TABLE_NAME] RENAME TO [NEW_NAME_FOR_TABLE]','{default}');
Change the name of a database table without a primary key
selectpglogical.replicate_ddl_command('ALTER TABLE [SCHEMA].[TABLE_NAME] RENAME TO [NEW_NAME_FOR_TABLE]','{default_insert_only}');
Create a database table with a primary key
Run the following commands:
selectpglogical.replicate_ddl_command(command:='CREATE TABLE [SCHEMA].[TABLE_NAME] (id INTEGER PRIMARY KEY, name VARCHAR);',replication_sets:=ARRAY['default']);
selectpglogical.replicate_ddl_command(command:='CREATE TABLE [SCHEMA].[TABLE_NAME] (id INTEGER PRIMARY KEY, name VARCHAR);',replication_sets:=ARRAY['default_insert_only']);
Large objects
can't be replicated, as PostgreSQL's logical decoding facility does not support
decoding changes to large objects. For tables that have column type
oid
referencing large objects, the rows are synced, and new rows are replicated.
However, trying to access the large object on the destination database
(read using lo_get,
export using lo_export,
or check the catalog pg_largeobject for the given
oid), fails with a message saying that the large object does
not exist.
For tables that don't have primary keys, Database Migration Service supports migration of the initial snapshot and INSERT statements during the change data capture (CDC) phase. You should migrate UPDATE and DELETE statements manually.
Database Migration Service doesn't migrate data from materialized views, just the view schema. To populate the views, run the following command: REFRESH MATERIALIZED VIEW view_name.
The SEQUENCE states (for example, last_value) on the new destination might vary from the source SEQUENCE states.
Customized tablespaces aren't supported in the destination Cloud SQL instance. All the data inside customized tablespaces is migrated to the default pg_default tablespace in Cloud SQL.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-25 UTC."],[[["\u003cp\u003eDatabase Migration Service ensures high-fidelity migration of database objects, including schema, data, and metadata, from one database to another.\u003c/p\u003e\n"],["\u003cp\u003eDuring migration, all tables, naming, primary keys, data types, default values, nullability, auto-increment attributes, secondary indexes, stored procedures, functions, triggers, views, and foreign key constraints are migrated.\u003c/p\u003e\n"],["\u003cp\u003eDuring continuous migrations, only data manipulation language (DML) changes are updated automatically, while data definition language (DDL) changes are managed by the user to maintain source and destination compatibility.\u003c/p\u003e\n"],["\u003cp\u003eDatabase Migration Service does not migrate large objects, \u003ccode\u003eUPDATE\u003c/code\u003e and \u003ccode\u003eDELETE\u003c/code\u003e statements for tables without primary keys, data from materialized views, and it migrates customized tablespaces to the default tablespace in the destination.\u003c/p\u003e\n"],["\u003cp\u003eThe \u003ccode\u003eSEQUENCE\u003c/code\u003e states on the destination database might differ from those on the source database after the migration.\u003c/p\u003e\n"]]],[],null,["# Migration fidelity\n\n\u003cbr /\u003e\n\n[MySQL](/database-migration/docs/mysql/migration-fidelity \"View this page for the MySQL version of Database Migration Service.\") \\| [PostgreSQL](/database-migration/docs/postgres/migration-fidelity \"View this page for the PostgreSQL version of Database Migration Service.\") \\| PostgreSQL to AlloyDB\n\n\u003cbr /\u003e\n\n\u003cbr /\u003e\n\n\u003cbr /\u003e\n\nOverview\n--------\n\nWhen you're migrating your schema, data, and metadata from a source database to a\ndestination database, you want to ensure that all of this information is\nmigrated accurately. Database Migration Service provides a high-fidelity way to\nmigrate database objects (including the schema, data, and metadata) from one\ndatabase to another.\n\nAll of the following data, schema, and metadata components are migrated as part\nof the database migration:\n\n### Data\n\n- All tables from all databases and schemas, excluding the following schemas:\n\n - The information schema `information_schema`\n - Any schemas beginning with `pg` (for example, `pg_catalog`)\n\n For more information about these schemas, see [Known limitations](/database-migration/docs/postgresql-to-alloydb/known-limitations).\n\n### Schema\n\n- Naming\n\n- Primary key\n\n- Data type\n\n- Ordinal position\n\n- Default value\n\n- Nullability\n\n- Auto-increment attributes\n\n- Secondary indexes\n\n### Metadata\n\n- Stored procedures\n\n- Functions\n\n- Triggers\n\n- Views\n\n- Foreign key constraints\n\n### Continuous migration\n\nOnly data manipulation language (DML) changes are updated automatically during\ncontinuous migrations. Managing data definition language (DDL) changes so that the source and destination databases remain compatible is the\nresponsibility of the user, and can be achieved in two ways:\n\n1. Stopping writes to the source and running the DDL commands in both source and destination. Before running DDL commands on the destination, grant `alloydbexternalsync` to the AlloyDB user applying the DDL changes. To enable querying or changing the data, grant the `alloydbexternalsync` role to the relevant AlloyDB users.\n2. Using the `pglogical.replicate_ddl_command` to allow DDL to be run on the source and destination at a consistent point. The user running this command must have the same username on both the source and the destination, and should be the superuser or the owner of the artifact being migrated (for example, the table, sequence, view, or database).\n\n Here are a few examples of using the `pglogical.replicate_ddl_command`.\n\n Replace:\n - \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e with the name of the table schema you want to use\n - \u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e with the table name\n - \u003cvar label=\"new_table_name\" translate=\"no\"\u003e[NEW_NAME_FOR_TABLE]\u003c/var\u003e with the new name for the table when when performing the rename operation\n\n #### Add a column to a database table with a primary key\n\n \u003cbr /\u003e\n\n ```sql\n select pglogical.replicate_ddl_command(\n 'ALTER TABLE \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e add column surname varchar(20)',\n '{default}'\n );\n ```\n\n \u003cbr /\u003e\n\n #### Add a column to a database table without a primary key\n\n \u003cbr /\u003e\n\n ```sql\n select pglogical.replicate_ddl_command(\n 'ALTER TABLE \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e add column surname varchar(20)',\n '{default_insert_only}'\n );\n ```\n\n \u003cbr /\u003e\n\n #### Change the name of a database table with a primary key\n\n \u003cbr /\u003e\n\n ```sql\n select pglogical.replicate_ddl_command(\n 'ALTER TABLE \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e RENAME TO \u003cvar label=\"new_table_name\" translate=\"no\"\u003e[NEW_NAME_FOR_TABLE]\u003c/var\u003e',\n '{default}'\n );\n ```\n\n \u003cbr /\u003e\n\n #### Change the name of a database table without a primary key\n\n \u003cbr /\u003e\n\n ```sql\n select pglogical.replicate_ddl_command(\n 'ALTER TABLE \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e RENAME TO \u003cvar label=\"new_table_name\" translate=\"no\"\u003e[NEW_NAME_FOR_TABLE]\u003c/var\u003e',\n '{default_insert_only}'\n );\n ```\n\n \u003cbr /\u003e\n\n #### Create a database table with a primary key\n\n Run the following commands:\n 1.\n\n ```sql\n select pglogical.replicate_ddl_command(\n command := 'CREATE TABLE \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e\n (id INTEGER PRIMARY KEY, name VARCHAR);',\n replication_sets := ARRAY['default']\n );\n ```\n 2.\n\n ```sql\n select pglogical.replication_set_add_table('default', '\u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e');\n ```\n\n \u003cbr /\u003e\n\n #### Create a database table without a primary key\n\n Run the following commands:\n 1.\n\n ```sql\n select pglogical.replicate_ddl_command(\n command := 'CREATE TABLE \u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e\n (id INTEGER PRIMARY KEY, name VARCHAR);',\n replication_sets := ARRAY['default_insert_only']\n );\n ```\n 2.\n\n ```sql\n select pglogical.replication_set_add_table(\n 'default_insert_only', '\u003cvar label=\"schema\" translate=\"no\"\u003e[SCHEMA]\u003c/var\u003e.\u003cvar label=\"table\" translate=\"no\"\u003e[TABLE_NAME]\u003c/var\u003e'\n );\n ```\n\n \u003cbr /\u003e\n\n### What isn't migrated\n\n- [Large objects](https://www.postgresql.org/docs/current/largeobjects.html)\n can't be replicated, as PostgreSQL's logical decoding facility does not support\n decoding changes to large objects. For tables that have column type\n [`oid`](https://www.postgresql.org/docs/current/datatype-oid.html)\n referencing large objects, the rows are synced, and new rows are replicated.\n However, trying to access the large object on the destination database\n (read using [`lo_get`](https://www.postgresql.org/docs/current/lo-funcs.html),\n export using [`lo_export`](https://www.postgresql.org/docs/current/lo-funcs.html),\n or check the catalog `pg_largeobject` for the given\n `oid`), fails with a message saying that the large object does\n not exist.\n\n- For tables that don't have primary keys, Database Migration Service supports migration of the **initial snapshot and `INSERT` statements during the change data capture (CDC) phase** . You should migrate `UPDATE` and `DELETE` statements manually.\n\n- Database Migration Service doesn't migrate data from materialized views, just the view schema. To populate the views, run the following command: `REFRESH MATERIALIZED VIEW `\u003cvar translate=\"no\"\u003eview_name\u003c/var\u003e.\n\n- The `SEQUENCE` states (for example, `last_value`) on the new destination might vary from the source `SEQUENCE` states.\n\n- Customized tablespaces aren't supported in the destination Cloud SQL instance. All the data inside customized tablespaces is migrated to the default `pg_default` tablespace in Cloud SQL."]]