Snowflake to Postgres sync that serves models back to your app
The Snowflake to Postgres sync from Adapters pushes warehouse tables and dbt models from Snowflake back into a Postgres application database on an incremental schedule, casting Snowflake types to Postgres and upserting on the primary key, so your app reads modeled data with a low-latency SQL query instead of hitting the warehouse on every request. Field mapping is no-code, so try it against sample records in the live demo.
No credit card required.
Field mapping auto-plugged · tap a port to rewire
Plug a source port into
Transform on this cable
JSON in
JSON out
5 sample records ready
Last updated September 2026
What running Snowflake to Postgres by hand costs you
- Serving a Snowflake table to your application means a slow, expensive warehouse query on every page load, so teams cache it by hand and the copy drifts.
- Snowflake and Postgres disagree on types: NUMBER precision, VARIANT and ARRAY, and the uppercase unquoted-identifier rule all need deliberate casting or numbers and column names land wrong.
- Reverse ETL scripts that push scores and segments back to the app fail silently and nobody notices until a feature shows stale data.
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 / SNOWFLAKE
Output / POSTGRES
Transforms included
Incremental runs use a Snowflake watermark column so only changed rows unload; NUMBER casts to Postgres NUMERIC at its declared precision, VARIANT and ARRAY land as JSONB so nested payloads survive, uppercase Snowflake identifiers fold to your Postgres naming, TIMESTAMP_NTZ and TIMESTAMP_TZ normalize to TIMESTAMPTZ in UTC, and writes upsert with ON CONFLICT on the primary key so a re-run window updates in place instead of duplicating rows.
Snowflake to Postgres: identifier case, numeric precision, and why reverse ETL breaks quietly
This lane almost never fails loudly. The sync runs, rows land, and the numbers are subtly wrong or the column names are not what the application expects. That is because Snowflake and PostgreSQL both normalize identifiers and both have opinions about numeric types, and their opinions are opposites. Below: the four conversions worth setting by hand, the write pattern that survives a re-run, and when this direction is the wrong design entirely. Snowflake documentation read 13 August 2026, PostgreSQL 18 documentation read 16 August 2026.
Both databases fold identifiers, in opposite directions
This is the first thing that bites and it looks like a typo rather than a rule. Snowflake folds unquoted identifiers to UPPERCASE, so a table created as orders is really ORDERS. PostgreSQL folds unquoted identifiers to lowercase, so the same statement there gives you orders. Move data between them without deciding a convention and you get a Postgres table containing a column literally named "TOTAL_USD", quoted, which every subsequent query then has to quote as well. Anyone who forgets gets a "column does not exist" error on a column they can plainly see. Pick lowercase unquoted names on the Postgres side and map explicitly from the uppercase Snowflake names. Do it at the start, because renaming a column that an application already reads is a deploy, not a mapping change.
NUMBER defaults to (38,0), which quietly deletes your cents
Snowflake's NUMBER type takes a default precision and scale of (38,0) when you do not specify one, and its maximum precision is 38. A scale of zero means no decimal places. If a model in Snowflake computed a revenue figure into a bare NUMBER column, the value was already rounded to whole units before it ever reached your pipeline, and no amount of care on the Postgres side recovers the fractions. When the Snowflake column does carry a scale, map it to NUMERIC at that same declared precision and scale, never to double precision. Floating point is the other way money gets damaged in this lane: the value looks right in a spreadsheet and then a sum over a hundred thousand rows disagrees with the ledger by a few dollars, which is exactly the kind of discrepancy that costs a day to find.
Three Snowflake timestamp types, two Postgres ones
Snowflake has TIMESTAMP_NTZ with no time zone, TIMESTAMP_LTZ which renders in the session zone, and TIMESTAMP_TZ which stores an offset. PostgreSQL has TIMESTAMP and TIMESTAMPTZ, and only the second one knows anything about zones. The safe mapping is TIMESTAMP_TZ and TIMESTAMP_LTZ to TIMESTAMPTZ, normalized to UTC, and TIMESTAMP_NTZ to plain TIMESTAMP. The trap is mapping an NTZ column into TIMESTAMPTZ, because PostgreSQL will then interpret those naive values using the server time zone, and every timestamp shifts by the offset. Nobody notices in a UTC-only shop. Everybody notices the following March, when daylight saving moves a report by an hour and the previous year's numbers no longer reconcile.
VARIANT, OBJECT and ARRAY belong in JSONB
Semi-structured Snowflake columns have one sensible destination in PostgreSQL and it is JSONB, not TEXT. Landing them as text works on the first day and costs you forever, because every read then has to parse the string, you cannot index into the document, and nothing stops a malformed payload arriving. JSONB gives you operators, GIN indexes and validation at write time. Size is worth checking before you design around it: Snowflake caps VARIANT, ARRAY and VARCHAR at 128 MB, with VARCHAR defaulting to 16 MB when you do not declare a length. Individual documents anywhere near those caps are a sign the warehouse is being used as a document store, and flattening the fields your application actually reads into real columns will serve it better than moving the blob.
Upsert on the key, because every schedule eventually re-runs a window
Reverse ETL writes into a database that is serving live traffic, so the write pattern matters more than in a warehouse load. Insert-only loading duplicates rows the first time a run overlaps a previous window, and it will overlap, whether from a retry, a clock skew or somebody re-running yesterday to fix a model. Write with INSERT ... ON CONFLICT (id) DO UPDATE so the operation is idempotent and a repeated window updates in place. Two related habits pay off here: keep the batch sizes modest so you are not holding long write transactions against tables the application is reading, and never make the sync the only writer of a column the app also sets, or the two will fight and the last run wins silently. Give warehouse-owned columns their own names.
When this direction is the wrong design, and how Adapters fits
Moving data from Snowflake back to Postgres is worth it when an application needs a modeled value on the hot path: a health score, a recommended price, a risk flag, a rolled-up lifetime total. It is not worth it when somebody simply wants to browse warehouse data, because that is a BI question and the warehouse already answers it. The test is whether a user-facing request would otherwise wait on a warehouse query. Adapters runs this pair as a scheduled incremental sync: a watermark on the Snowflake side so only changed rows unload, the type and identifier mapping above applied in a visual mapper rather than in a script somebody has to maintain, upserts on the primary key, and per-record error logs when a row fails to apply. The category as a whole, including the vendors that specialize in it, is compared on our reverse ETL tools page.
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 Snowflake 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 serving Snowflake tables from Postgres covers the field-by-field detail, the failure cases, and what changes at volume.
Snowflake to Postgres sync: common questions
How do I sync Snowflake to Postgres?
Point the connector at a Snowflake warehouse and role with read access, write a query or select the tables to move, map columns to the Postgres target, and schedule incremental runs on a timestamp or sequence column. An upsert on the primary key means a rerun updates rows rather than duplicating them.
Why would you move data from Snowflake back to Postgres?
Because an application cannot query a warehouse on the hot path. Models built in Snowflake (a customer health score, a recommended price, a risk flag) are only useful once they reach the operational database the product actually reads. That direction of travel is usually called reverse ETL, and it is the most common reason for this pair.
How do you map Snowflake types to Postgres?
NUMBER with a scale becomes NUMERIC and integer-scaled NUMBER becomes BIGINT, VARCHAR becomes TEXT, TIMESTAMP_NTZ becomes TIMESTAMP and TIMESTAMP_TZ becomes TIMESTAMPTZ, and VARIANT or OBJECT becomes JSONB. Watch identifier case in both directions: Snowflake folds unquoted names to uppercase and PostgreSQL folds them to lowercase, so pick lowercase targets and stay consistent.
How do you keep a Snowflake to Postgres sync incremental?
Give the source model a reliable updated-at column or a monotonic load sequence and filter on it each run. Full reloads of a warehouse table into an operational database are expensive on both sides and lock rows the application needs. Incremental upserts on the key keep the write volume proportional to what actually changed.
How does the Snowflake to Postgres sync work?
The Snowflake to Postgres sync from Adapters pushes warehouse tables and dbt models from Snowflake back into a Postgres application database on an incremental schedule, casting Snowflake types to Postgres and upserting on the primary key, so your app reads modeled data with a low-latency SQL query instead of hitting the warehouse on every request. Field mapping is no-code, so try it against sample records in the live demo.
Is there a prebuilt Snowflake connector for Postgres?
Yes. This Snowflake 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 Snowflake 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 Snowflake 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 Snowflake and Postgres?
No. Fields are auto-mapped the moment you pick the pair, and you can rewire any mapping visually before the first sync. Incremental runs use a Snowflake watermark column so only changed rows unload; NUMBER casts to Postgres NUMERIC at its declared precision, VARIANT and ARRAY land as JSONB so nested payloads survive, uppercase Snowflake identifiers fold to your Postgres naming, TIMESTAMP_NTZ and TIMESTAMP_TZ normalize to TIMESTAMPTZ in UTC, and writes upsert with ON CONFLICT on the primary key so a re-run window updates in place instead of duplicating rows.
More pairs from the API connector library
Browse the full api connector library, or request a pair you do not see.
Snowflake 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.
No credit card required.