Redshift to Snowflake migration: how to move warehouse tables without a reporting freeze
11 min read Data engineering The Adapters team
Last updated July 2026
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
To migrate Redshift to Snowflake, recreate the schema with Snowflake types (dropping distribution and
sort keys, mapping SUPER to VARIANT, keeping DECIMAL precision as
NUMBER), backfill each table through a cloud stage, then keep syncing changed rows on a
watermark so both warehouses run in parallel. Translate the SQL dialect differences in your models,
validate row counts and column sums side by side, repoint BI last, and keep Redshift readable for a
reporting cycle.
Key takeaways
- Run both warehouses in parallel. A big-bang cutover means a frozen reporting window and no way to compare numbers. Parallel running gives you a side-by-side diff instead of a leap of faith.
- Identifier case is the silent breaker. Redshift folds unquoted names to lowercase, Snowflake folds them to uppercase. Anything your models quoted will stop resolving.
- Dist keys and sort keys do not port. Snowflake has no distribution style. Drop them, then add clustering only on tables where it demonstrably pays.
- Most of the effort is SQL and BI, not data movement. Copying tables is the easy part; translating models and repointing dashboards is the schedule.
How do I migrate from Redshift to Snowflake?
Migrate in five phases: convert the schema to Snowflake types, backfill each table through a cloud stage, keep syncing changed rows so both warehouses stay in step, translate and re-run your SQL models against Snowflake until results match, then repoint BI tools and scheduled jobs table by table. Cut over gradually rather than all at once.
The schema conversion is mostly subtraction. Redshift DDL carries distribution style, distribution keys, sort keys, encodings, and compression settings, none of which Snowflake needs, because Snowflake manages micro-partitions itself. Strip them and you are left with column names, types, and constraints. Note that neither warehouse enforces primary keys, but Snowflake uses them as optimizer metadata, so declare them anyway and let your loads uphold uniqueness.
The backfill itself is straightforward: UNLOAD from Redshift to S3 in Parquet, then
COPY INTO from an external stage in Snowflake. Chunk large tables by a date or id range
so each unit is bounded and retriable. Load the biggest tables first, because they need the most time
to catch up incrementally and they are the ones most likely to surface a type problem.
For the ongoing parallel period, the Redshift to Snowflake connector handles the watermark, the type casting, and the idempotent merges, which is the part teams do not want to build for a migration that runs for a few weeks and then stops.
How do Redshift data types map to Snowflake?
Redshift and Snowflake share ANSI SQL roots, so most types map directly. The ones that need a decision
are SUPER (semi-structured, becomes VARIANT), VARCHAR length
(Redshift counts bytes, Snowflake counts characters), and timestamps, where Redshift
TIMESTAMP has no zone while TIMESTAMPTZ does.
| Redshift type | Snowflake type | Note |
|---|---|---|
| SMALLINT, INTEGER, BIGINT | NUMBER(38,0) | Snowflake has one integer family and no range risk. |
| DECIMAL(p,s), NUMERIC | NUMBER(p,s) | Redshift maxes at precision 38, same as Snowflake. Carry scale across exactly. |
| REAL, DOUBLE PRECISION | FLOAT | Snowflake FLOAT is double precision. Never use it for money. |
| VARCHAR(n) | VARCHAR(n) | Redshift n is BYTES, Snowflake n is CHARACTERS. Multibyte text needs a wider limit or it truncates. |
| CHAR(n) | VARCHAR(n) | Snowflake does not pad. Trailing-space comparisons may behave differently. |
| BOOLEAN | BOOLEAN | Direct. |
| DATE | DATE | Direct. |
| TIMESTAMP | TIMESTAMP_NTZ | No zone on either side. Keep it NTZ rather than silently gaining a UTC offset. |
| TIMESTAMPTZ | TIMESTAMP_TZ | Direct. Confirm the session timezone on both sides before comparing values. |
| SUPER | VARIANT | Both are semi-structured. Access paths differ, so queries touching SUPER need rewriting. |
| GEOMETRY, GEOGRAPHY | GEOGRAPHY | Function coverage differs. Test any spatial logic rather than assuming parity. |
| VARBYTE | BINARY | Direct, rarely used in analytics tables. |
| DISTKEY, SORTKEY, ENCODE | (none) | Drop them. Snowflake handles micro-partitioning; add clustering only where it earns the cost. |
| IDENTITY column | Sequence or IDENTITY | Supported, but analytics tables rarely need it once loads carry the source key. |
The VARCHAR row is the one that quietly loses data. A Redshift VARCHAR(20)
holds 20 bytes, which is only 20 characters for plain ASCII but far fewer for accented or non-Latin
text. Copy the declared lengths across unchanged and any multibyte value that already fit in Redshift
will still fit in Snowflake, since Snowflake counts characters, which is the more forgiving direction.
The failure happens in reverse, so it is worth confirming rather than assuming.
What SQL differences break after moving from Redshift to Snowflake?
The breakages cluster in four places: identifier case, semi-structured access, date functions, and Redshift-specific syntax with no Snowflake equivalent. None are conceptually hard, but they surface as dozens of small model failures, which is why the SQL translation phase usually takes longer than the data copy.
| Area | Redshift | Snowflake |
|---|---|---|
| Unquoted identifier case | Folds to lowercase | Folds to UPPERCASE |
| Semi-structured access | SUPER with dot and index notation | VARIANT with colon path, plus casting on extract |
| Date arithmetic | DATEADD, DATEDIFF, GETDATE() | DATEADD, DATEDIFF, CURRENT_TIMESTAMP() |
| String aggregation | LISTAGG | LISTAGG, with WITHIN GROUP ordering required |
| Table distribution | DISTSTYLE, DISTKEY, SORTKEY | Not supported; use clustering keys selectively |
| Vacuum and analyze | Manual VACUUM and ANALYZE maintenance | Automatic; remove the maintenance jobs entirely |
| Bulk load | COPY from S3 with a credentials clause | COPY INTO from a named external stage or storage integration |
| Result caching | Result cache per cluster | Result cache plus warehouse-level caching, different invalidation |
Deal with case first because it is the widest blast radius. If your Redshift DDL created objects
unquoted, they are lowercase, and any Snowflake object created unquoted is uppercase; a model that
references "orders" in double quotes will not find ORDERS. The clean fix is
to create everything in Snowflake unquoted and remove double quotes from your models, so both sides
fold consistently and case stops being something anyone has to think about.
The maintenance row is the pleasant surprise. VACUUM and ANALYZE jobs,
table-resize windows, and encoding tuning all disappear, which is real recurring engineering time you
get back and worth counting when you justify the move.
Is Snowflake cheaper than Redshift?
It depends on how steady your workload is. Redshift provisioned clusters bill for nodes whether or not anyone queries them, so a steady round-the-clock workload can be cost-effective there. Snowflake bills per second of warehouse runtime with auto-suspend, so spiky or business-hours workloads usually cost less, and idle time costs almost nothing.
The variable that decides it is your utilization curve, not the list price. A cluster busy 20 percent of the day is paying for 80 percent idle; a Snowflake warehouse suspended after sixty seconds is not. Conversely a warehouse left running with a generous auto-suspend, or a team that sizes every warehouse large by default, erases the advantage quickly. Both platforms also offer serverless or elastic options that change the math further, so read your own bill rather than a comparison table.
Model it before you commit. Pull the last ninety days of query history from Redshift, work out the hours where anything actually ran, and size Snowflake warehouses against that profile; connecting the cloud spend read-only and watching it per workload after cutover is what stops a migration justified on cost from quietly becoming more expensive. The first month on a new warehouse is when consumption habits form.
How do I validate a Redshift to Snowflake migration?
Validate with parallel queries: run the same aggregate on both warehouses for the same time window and compare. Per table, check row count, a sum over every numeric column, distinct counts on key dimensions, and min plus max on the primary timestamp. If all four agree across every table, the copy is trustworthy.
Then validate the layer above the tables, which is where migrations actually go wrong. Run your top twenty dashboards and scheduled reports against both warehouses and diff the outputs, because a model can compile cleanly against Snowflake and still return different numbers thanks to a null-handling difference, a changed sort order, or a date function that rounds the other way at a boundary. A table that matches row for row while its downstream metric differs by 2 percent is the failure mode worth hunting.
Keep the parallel period long enough to cover a full reporting cycle, usually a month, so a monthly close runs on both sides before you decommission anything. That is also the window in which you repoint BI tools one at a time rather than in a single afternoon.
How long does a Redshift to Snowflake migration take?
For a typical warehouse of a few hundred tables and a few hundred models, plan six to twelve weeks end to end, with no reporting downtime if you run in parallel. The data copy is days; the SQL translation, validation, and BI repointing are the schedule.
A rough split from how these projects tend to run: about a week for schema conversion and the first backfill, two to four weeks translating and re-running models until outputs match, two to four weeks of parallel operation covering at least one monthly close, and a final week repointing dashboards and decommissioning. Teams with heavy stored-procedure logic or many spatial and semi-structured queries sit at the longer end.
You can compress the middle by moving in slices rather than all at once. Pick one business domain, migrate its tables and models, validate it, repoint its dashboards, and repeat. Each slice teaches you something that makes the next faster, and you are never one failed cutover away from a reporting outage. If your target is Google Cloud instead, the same structure applies through the Snowflake and BigQuery migration guide, which covers the reverse type map in detail.
For the parallel-run sync itself, the Redshift to Snowflake connector maps the pair in the browser, casts types, and merges on the key at a flat monthly price rather than a per-row meter, which matters when a migration means moving the same tables repeatedly. You can also book a walkthrough against your own schema.
Run Redshift and Snowflake in parallel until the numbers agree
Watermark incrementals, Redshift to Snowflake type casting, SUPER to VARIANT, and MERGE loads that survive a replay. Map the pair in the browser and pay a flat price from $49 a month.
No credit card required.