Skip to content
adapters.io

SQL Server to PostgreSQL migration tool with schema conversion built in

The SQL Server to PostgreSQL connector from Adapters converts your schema, maps every T-SQL data type to its PostgreSQL equivalent, and then keeps both databases in step with incremental loads until you are ready to cut over. It runs the migration as a parallel sync rather than a one-shot dump, so you can prove the row counts match before you move the application.

The live demo needs no card, and Starter is $49 a month.

Field mapping auto-plugged · tap a port to rewire

5 sample records ready

What running SQL Server to Postgres by hand costs you

  • A one-shot dump and restore gives you no way to prove the numbers match, so the cutover turns into a weekend nobody wants to sign off on.
  • SQL Server preserves the case you typed an identifier in while PostgreSQL folds unquoted identifiers to lowercase, so a lift and shift silently breaks every query that referenced CustomerID.
  • MONEY, DATETIMEOFFSET, and UNIQUEIDENTIFIER are the three columns a generic converter gets wrong, and each one costs you either precision, a time zone, or a join.

The field mapping, out of the box

These cables are pre-wired when you pick the pair. Rewire any of them, or add your own, in the same visual data mapping tool you use for every adapter.

Input / SQLSERVER

dbo.Orders.OrderID
orders.id
dbo.Customers.Email
customers.email
dbo.Customers.FullName
customers.full_name
dbo.Orders.TotalAmount
orders.total_amount
dbo.Orders.ModifiedDate
orders.created_at
dbo.Orders.Status
orders.status

Transforms included

Identifiers fold to lowercase snake_case on the way across so you never have to double quote a mixed-case column in PostgreSQL again. MONEY and SMALLMONEY become NUMERIC(19,4) rather than the PostgreSQL MONEY type, which is locale dependent. DATETIME becomes TIMESTAMP(3), DATETIME2 keeps its declared precision as TIMESTAMP(p), and DATETIMEOFFSET is the only type that becomes TIMESTAMPTZ. BIT becomes BOOLEAN, UNIQUEIDENTIFIER becomes a native UUID, NVARCHAR(MAX) and the deprecated NTEXT become TEXT, VARBINARY becomes BYTEA, and incremental runs read a ModifiedDate watermark or the CDC change tables, then upsert on the primary key so a replayed batch never duplicates a row.

SQL Server to Postgres: the type map, identifier case, and what CDC costs on the source

Two things decide whether this migration is calm or expensive: whether the type map was written by someone who knew which T-SQL types have no honest Postgres equivalent, and whether you turned on SQL Server change data capture without reading what it does to the transaction log. Below: the conversions that matter, the case rule that renames half your schema, and the CDC mechanics worth knowing before you enable it. Microsoft Learn read 4 August 2026, PostgreSQL 18 documentation read 16 August 2026.

The type map worth setting by hand

Most T-SQL types have an obvious Postgres counterpart and a few do not. TINYINT is unsigned 0 to 255 in SQL Server and has no unsigned equivalent, so it becomes smallint. DATETIME2(p) becomes timestamp(p), keeping the precision you declared. UNIQUEIDENTIFIER becomes native uuid, not char(36), because the native type is half the storage and comparisons are integer comparisons. NVARCHAR becomes text or varchar(n), since PostgreSQL databases are typically UTF-8 throughout and the N prefix stops meaning anything. BIT becomes boolean. The one that needs a rule rather than a lookup is DATETIMEOFFSET, covered below, and the one that ruins a finance report is MONEY.

Never map MONEY to Postgres MONEY

PostgreSQL has a type called money and it is the wrong destination for SQL Server's MONEY. The Postgres type depends on the database lc_monetary setting for both output format and interpretation, which makes stored values sensitive to a server configuration that has nothing to do with your data, and it makes dumps less portable than they look. Map MONEY to numeric(19,4) instead, which matches the four decimal places SQL Server actually stores and keeps exact decimal arithmetic. The same reasoning rules out double precision for any currency column: floating point sums drift, and the drift shows up as a small unexplained difference between a dashboard and the ledger, discovered weeks later by an accountant rather than by a test.

DATETIMEOFFSET is the only type that earns TIMESTAMPTZ

This is the rule that prevents the most common silent corruption in this lane. Of all the SQL Server date and time types, only DATETIMEOFFSET actually stores a zone offset. DATETIME, SMALLDATETIME and DATETIME2 store naive local values with no zone information whatsoever. So DATETIMEOFFSET maps to timestamptz, and everything else maps to plain timestamp. Map a naive DATETIME2 into timestamptz and PostgreSQL interprets those values using the server time zone, shifting every timestamp in the column by the offset. In a US business running on Eastern time that is a five hour error, which is enough to move transactions across a day boundary and change what lands in a monthly close.

Identifier case flips, and it renames your whole schema

SQL Server preserves the case you typed when you created an object, so CustomerOrders stays CustomerOrders and, under the usual case-insensitive collation, you can also refer to it as customerorders. PostgreSQL folds unquoted identifiers to lowercase, so the same CREATE TABLE CustomerOrders produces a table genuinely named customerorders. You have two coherent options and one bad one. Coherent: convert everything to snake_case as part of the migration, which is idiomatic Postgres and means nothing ever needs quoting. Also coherent: preserve the original names in double quotes everywhere. The bad option is doing neither consistently, which leaves a schema where some objects need quoting and others do not, and every developer discovers the rule by hitting an error.

What SQL Server CDC actually costs on the source

If you want log-based capture rather than a watermark query, SQL Server has native CDC, and it is a real feature with real operational weight. The capture job reads the transaction log through sp_replcmds and requires SQL Server Agent to be running, which rules it out on managed tiers where Agent is unavailable. By default the capture process handles up to 1,000 transactions per cycle with a 5 second wait between scans, and a cleanup job runs daily at 2 AM retaining 4,320 minutes of change data, which is three days. Changes arrive in the change tables with an __$operation column where 1 is delete, 2 is insert, 3 is the before image of an update and 4 is the after image. Consume the 4 rows and ignore the 3 rows unless you are auditing.

The log truncation trap, and how Adapters fits

The detail that surprises database administrators: once CDC is enabled, the log truncation point does not advance until the capture process has gathered the changes, even when the database is in SIMPLE recovery mode. Teams assume SIMPLE means the log manages itself, so when the capture job is stopped or falls behind, the transaction log grows and nobody connects it to the CDC feature somebody enabled for the migration. Monitor capture job latency and alert on it, exactly as you would alert on a PostgreSQL replication slot. If that operational weight is not worth it, a watermark query on a reliable modified-date column costs nothing on the source, and its only real gap is that it cannot see hard deletes. Adapters runs this pair either way: watermark by default, with the type map above applied in a visual mapper and per-record error logs on the rows a cast rejects.

How it goes live

Three steps, minutes end to end, covered by flat data integration pricing from $49 a month.

STEP 01

Pick the pair

Connect SQL Server and Postgres with scoped credentials. About a minute each.

STEP 02

Confirm the mapping

The cables above are pre-wired. Adjust any field, preview the transform on sample records, done.

STEP 03

Schedule the sync

Hourly down to every minute, with retries, alerting, and a full log on every run.

Prefer to understand the moving parts first? Our long-form guide to the SQL Server to PostgreSQL migration guide covers the field-by-field detail, the failure cases, and what changes at volume.

Try it in the live demo Preloads SQLSERVER → POSTGRES with sample records

SQL Server to Postgres sync: common questions

How do I migrate a SQL Server database to PostgreSQL?

Convert the schema first, backfill each table once from a replica, then keep both databases in step with incremental loads while you port the application. Running the two in parallel for a couple of weeks is what lets you compare totals and cut over on a weekday instead of a weekend.

What is the SQL Server to PostgreSQL data type mapping?

INT stays INT, NVARCHAR becomes VARCHAR(n) or TEXT, and BIT becomes BOOLEAN. The four worth deciding by hand are MONEY, which should become NUMERIC(19,4), DATETIME2, which becomes TIMESTAMP(p), DATETIMEOFFSET, which is the only type that earns TIMESTAMPTZ, and UNIQUEIDENTIFIER, which becomes a native UUID.

Why does my query break after migrating from SQL Server to PostgreSQL?

Usually identifier case. PostgreSQL folds unquoted identifiers to lowercase, so a column created as CustomerID is physically customerid unless the DDL quoted it. Fold every name to lowercase at conversion time and lowercase the application references, rather than quoting mixed case forever.

Is PostgreSQL cheaper than SQL Server?

PostgreSQL has no license fee at all. Microsoft lists SQL Server 2022 Enterprise at $15,123 per two-core pack and Standard at $3,945, so a modest 16-core Enterprise instance carries roughly $121,000 in list licensing before support. You still pay for hardware, hosting, and people either way.

Can I migrate SQL Server stored procedures to PostgreSQL automatically?

Partly. Tables, indexes, constraints, and views convert mechanically, but T-SQL and PL/pgSQL differ enough that procedural code needs a human. Budget your migration timeline around the stored procedures and reports, not the data volume, because bulk loading rows is the fast part.

How do I keep SQL Server and PostgreSQL in sync during the migration?

Read only rows that changed since the last run using an indexed ModifiedDate watermark, or read the CDC change tables when you also need deletes, then upsert on the primary key. Advance the stored watermark only after the upsert commits, so a failed run repeats its window instead of skipping rows.

How does the SQL Server to Postgres sync work?

The SQL Server to PostgreSQL connector from Adapters converts your schema, maps every T-SQL data type to its PostgreSQL equivalent, and then keeps both databases in step with incremental loads until you are ready to cut over. It runs the migration as a parallel sync rather than a one-shot dump, so you can prove the row counts match before you move the application.

Is there a prebuilt SQL Server connector for Postgres?

Yes. This SQL Server to Postgres connector ships prebuilt: the field mapping is wired the moment you pick the pair, transforms are included, and you can try it against sample records in the live demo. No code or engineering sprint required.

How much does the SQL Server Postgres integration cost?

Pricing is flat and monthly: Starter at $49, Growth at $149, Scale at $399. Every plan includes this pair, visual field mapping, and per-record logs. There are no per-task or per-row fees, so the bill stays the same as volume grows.

How often can Adapters sync SQL Server to Postgres?

Hourly on Starter, every 5 minutes on Growth, and down to every minute on Scale. Failed records retry automatically with backoff, and alerting plus a full per-record log come standard on every run.

Do I need to write code to connect SQL Server and Postgres?

No. Fields are auto-mapped the moment you pick the pair, and you can rewire any mapping visually before the first sync. Identifiers fold to lowercase snake_case on the way across so you never have to double quote a mixed-case column in PostgreSQL again. MONEY and SMALLMONEY become NUMERIC(19,4) rather than the PostgreSQL MONEY type, which is locale dependent. DATETIME becomes TIMESTAMP(3), DATETIME2 keeps its declared precision as TIMESTAMP(p), and DATETIMEOFFSET is the only type that becomes TIMESTAMPTZ. BIT becomes BOOLEAN, UNIQUEIDENTIFIER becomes a native UUID, NVARCHAR(MAX) and the deprecated NTEXT become TEXT, VARBINARY becomes BYTEA, and incremental runs read a ModifiedDate watermark or the CDC change tables, then upsert on the primary key so a replayed batch never duplicates a row.

More pairs from the API connector library

stripe quickbooks integration shopify netsuite integration salesforce hubspot integration airtable google sheets sync postgres to snowflake sync shopify quickbooks integration salesforce netsuite integration paypal quickbooks integration square quickbooks integration stripe netsuite integration hubspot quickbooks integration quickbooks to xero migration shopify xero integration salesforce to snowflake integration square netsuite integration hubspot xero integration salesforce to bigquery integration postgres to bigquery netsuite to snowflake integration quickbooks to bigquery integration stripe to snowflake integration shopify to snowflake integration quickbooks to snowflake integration hubspot to snowflake integration netsuite to bigquery integration stripe to bigquery integration shopify to bigquery integration paypal to snowflake integration square to snowflake integration square to bigquery integration netsuite to postgres integration salesforce to postgres integration xero to snowflake integration hubspot to bigquery integration xero to bigquery integration paypal to bigquery integration stripe to postgres integration snowflake to bigquery migration shopify to postgres integration hubspot to postgres integration bigquery to snowflake migration quickbooks to postgres integration xero to postgres integration square to postgres integration paypal to postgres integration snowflake to postgres mysql to postgres migration mysql to snowflake redshift to snowflake migration mysql to bigquery sql server to snowflake

Browse the full api connector library, or request a pair you do not see.

SQL Server and Postgres, finally in agreement

Map the pair once and let it sync on schedule. Flat price from $49 a month, no per-task fees.

The live demo needs no card, and Starter is $49 a month.

Get started