Skip to content
adapters.io

SQL Server to Snowflake migration tools compared: converters, data type mapping, cost, and eight published mappings that change your data

Twelve tools that move a SQL Server database into Snowflake, and the part no feature list covers. We took the type mappings published in Snowflake's own SnowConvert translation reference and checked each one against the documentation of the product it describes. Eight do not survive the check, including an integer range that stops being enforced and a constraint model that accepts your primary keys and then ignores them. All four tables are below, with the query that catches each failure before it reaches production.

Try the live demo

No credit card required.

Field mapping auto-plugged · tap a port to rewire

5 sample records ready

Vendor documentation read 2 September 2026 · Last updated September 2026

Which SQL Server to Snowflake migration tool should you use?

Use SnowConvert for the schema and stored procedure conversion. It is free, Snowflake builds it for this exact route, and it produces an assessment report you can scope a timeline from. Move the rows separately: a change data capture tool such as AWS DMS or a managed connector when you need the cutover measured in seconds, or native COPY INTO from staged Parquet when the move is one time and you can take downtime. Whichever you choose, do not accept the default type mapping and do not assume your constraints came with you. Snowflake accepts PRIMARY KEY, UNIQUE and FOREIGN KEY definitions on standard tables and then does not enforce any of them. Only NOT NULL and CHECK are always enforced, which makes CHECK the tool you rebuild your lost guarantees with.

The correction worth making early: this category ranks tools by how much of the schema they convert, which is close to meaningless because nearly everything in a SQL Server schema is an ordinary table that every tool converts. The question that decides whether the migration succeeds is what happens to the dozen types and the one constraint model where the two engines genuinely disagree, and whether the tool tells you. For the wider category see data migration tools, and for the ongoing load rather than the one time move, Snowflake ETL tools.

Eight published mapping claims that the other vendor's own docs contradict

The SnowConvert Transact-SQL translation reference is the most detailed public mapping for this route, and it is genuinely useful. It is also, in places, wrong or incomplete in ways that are checkable in about five minutes. We took the mappings it publishes and compared each against the primary documentation of the product being described, on 2 September 2026. Eight did not survive. Three are contradicted by another page of the same vendor's own documentation.

Type or claim What the mapping says What contradicts it What we would ship
SMALLINT The SnowConvert Transact-SQL data type reference maps SMALLINT to SMALLINT and notes "Behaves equally on both systems" Snowflake's own numeric data types page says SMALLINT is "Synonymous with NUMBER, except that precision and scale can't be specified (that is, it always defaults to NUMBER(38, 0))", with a range of 38 digits. The adjacent rows of the same mapping table say exactly that about BIGINT, INT and TINYINT. Microsoft gives SQL Server smallint as -32,768 to 32,767 in two bytes. NUMBER(38,0) plus an explicit CHECK if the range was load bearing
TINYINT Maps to TINYINT, correctly noted as "an alias for NUMBER(38,0)" Accurate about Snowflake and silent about the consequence. Microsoft gives SQL Server tinyint as 0 to 255 in a single byte, unsigned. The target accepts negatives and 38 digit values, so a status column that could not physically hold -1 now can, and nothing will tell you when it does. NUMBER(38,0) with CHECK (col BETWEEN 0 AND 255)
DATETIME Maps to TIMESTAMP_NTZ(3) The precision is right and the rounding is unmentioned. Microsoft documents datetime accuracy as "Rounded to increments of .000, .003, or .007 seconds", and its own worked example stores 01/01/2024 23:59:59.999 as 2024-01-02 00:00:00.000, which is the next day. Those rows already sit in the wrong day in SQL Server. TIMESTAMP_NTZ(3), and reconcile daily counts on the source before blaming the loader
SMALLDATETIME Maps to TIMESTAMP_NTZ with the note "DATETIME truncates the TIME information" Microsoft's conversion example shows hours and minutes are copied and only seconds and fractional seconds are set to zero: a smalldatetime of 12:32 becomes 2016-12-01 12:32:00.000. The time is rounded to the minute, not truncated away. Acting on the note as written loses the time of day. TIMESTAMP_NTZ(0)
UNIQUEIDENTIFIER Maps to VARCHAR A sensible target with an unmentioned side effect. Microsoft states that for uniqueidentifier "ordering is not implemented by comparing the bit patterns of the two values". Once the column is a string, Snowflake orders it by Unicode code point, so ORDER BY on that column returns a different sequence than it did in SQL Server. VARCHAR(36), and re-derive any ORDER BY or keyset pagination built on the GUID
REAL Maps to REAL, noted as "Snowflake's REAL is synonymous with FLOAT" True of the target and misleading about the source. Snowflake's numeric page states FLOAT, REAL and DOUBLE are all treated as 64 bit IEEE 754. SQL Server real is a four byte float carrying roughly seven digits. The column silently widens, so stored approximations begin displaying digits the source never showed. FLOAT, with money and quantities moved to NUMBER instead of any float
The VARCHAR maximum The same mapping table prints the Snowflake character maximum as 167772161 Snowflake's text data types page gives the maximum as 134,217,728 bytes (128 MB) and the default, when no length is specified, as 16,777,216. The printed figure matches neither number, and it is the figure teams use to decide whether an NVARCHAR(MAX) column will fit. VARCHAR with no length declared for anything that was VARCHAR(MAX) or NVARCHAR(MAX)
Constraint enforcement The summary repeated across this category, including Snowflake's own constraints overview page, is that NOT NULL is the only constraint a standard table enforces Snowflake's constraints page states it "doesn't enforce them, except for NOT NULL and CHECK constraints, which are always enforced". CHECK is enforced on standard tables. That is not a footnote: it is what makes the range guards lost in the first two rows rebuildable rather than merely regrettable. Rebuild the guards you lost as CHECK constraints, and stop treating Snowflake as constraint free

None of this makes the reference useless and we still recommend running SnowConvert first. It makes the point that a published mapping is a starting position rather than a fact. The last row is the one to sit with, because it runs the other way: the claim repeated everywhere in this category, that Snowflake enforces nothing but NOT NULL, is now out of date. CHECK constraints are enforced on standard tables. That single sentence is the difference between losing every integer range guard in your schema and rebuilding them in an afternoon.

Snowflake publishes two SQL Server mappings and they disagree

The section above checks one vendor document against another vendor's documentation. This one is narrower and harder to argue with: Snowflake publishes two separate descriptions of how a SQL Server column becomes a Snowflake column, the Openflow Connector for SQL Server data mapping page and the SnowConvert Transact-SQL data type reference, and they do not agree. Both are Snowflake's own. Neither acknowledges the other. We read both against Microsoft Learn on 6 September 2026, and the row that should stop a migration plan is the first one. Note also that the Openflow mapping states it applies to both the standard and the CDC variant of the connector, so switching variant does not change any of this.

Column type Openflow connector SnowConvert Why it matters What we would ship
GEOGRAPHY TEXT, and "values of this type are inserted as NULL" GEOGRAPHY, a real Snowflake spatial type The widest gap on this page. Plan the migration from the SnowConvert reference, which is the document most teams read because it is the more detailed one, and you will expect a working spatial column. Execute it with Snowflake's own connector and every value arrives NULL. Both documents are Snowflake's. Neither mentions the other. GEOGRAPHY, loaded from WKT outside the connector
GEOMETRY TEXT, inserted as NULL No target defined, marked unsupported Both fail, and they fail differently, which is worse than either failing consistently. SnowConvert tells you up front that you have work to do. The connector does not, and a NULL column looks like a column with no data in it rather than a column that was silently discarded. Re-derive as GEOGRAPHY in WGS84, or store WKT deliberately
ROWVERSION / TIMESTAMP TEXT BINARY(8) Microsoft settles this one. Its rowversion page states the type "is just an incrementing number and does not preserve a date or a time", and that a non-nullable rowversion column "is semantically equivalent to a binary(8) column". SnowConvert matches Microsoft exactly. The connector does not, and a hex string is a poor substitute when the column exists to be compared. BINARY(8), plus a real updated_at for concurrency
DECIMAL and NUMERIC above 38 digits The value "is stored as TEXT" DECIMAL or NUMERIC, with no overflow rule stated One document tells you what happens on overflow and the other does not raise the possibility. Worth knowing that Snowflake's MySQL connector, the same product family, answers this same condition a third way again: it says precision is lost, which returns a shorter number that still adds up rather than a string that breaks loudly. NUMBER(38,s) by hand, scale from real magnitudes
MONEY and SMALLMONEY NUMBER, with no scale stated NUMBER(38,4) SnowConvert is right and specific here, and Microsoft supports it: money is documented as accurate to a ten-thousandth of the currency unit, which is four decimal places. An unstated scale is the one you least want to inherit on a currency column, because NUMBER with no arguments defaults to NUMBER(38,0) and that is zero decimal places. NUMBER(38,4), spelled out, on every money column
Temporal precision Bare TIMESTAMP_NTZ for DATETIME, DATETIME2 and SMALLDATETIME, bare TIMESTAMP_TZ for DATETIMEOFFSET TIMESTAMP_NTZ(3), TIMESTAMP_NTZ(7) and TIMESTAMP_TZ(7) respectively The connector collapses three source types with three different precisions into one unqualified target. SnowConvert preserves the distinction. Neither is wrong about what Snowflake accepts, and only one of them records that a datetime was accurate to milliseconds while a datetime2 was accurate to a hundred nanoseconds. Declare the precision, matching SnowConvert
XML TEXT VARIANT A real fork in the road rather than an error. VARIANT gives you semi-structured querying over the document; TEXT gives you a string you must parse at query time. Both are defensible and they are not interchangeable, and whichever one you get depends on which Snowflake document your vendor implemented. VARIANT if anything queries inside it, TEXT if archival
SQL_VARIANT TEXT VARIANT Same fork, sharper consequence. SQL_VARIANT exists precisely because the column holds values of differing types, which is what VARIANT is for. Flattening it to TEXT throws away the type information that was the reason the column existed, and anything relying on SQL_VARIANT_PROPERTY needs rewriting either way. VARIANT, and rewrite the SQL_VARIANT_PROPERTY calls

The practical lesson is that the document you plan from and the tool you execute with have to be the same decision. Reading the more detailed reference and then running the connector is how a team ends up with a spatial column full of NULLs and a currency column rounded to whole dollars. The same vendor behaves the same way on the neighboring route: its MySQL to Snowflake connector maps that database's BIT to a hexadecimal string while this one maps SQL Server's BIT to a real BOOLEAN. The column-by-column version, with a query that proves each risky one before you load it, is in convert SQL Server data types to Snowflake.

SQL Server to Snowflake migration tools compared

Pricing models rather than price tags, because every vendor here except us either quotes or meters, and any figure printed on this page would be stale within a quarter. Where a tool is wrong for a job, the last column says so.

Tool Approach Best for Pricing model
SnowConvert Static code conversion: reads SQL Server DDL and T-SQL, emits Snowflake SQL plus an assessment report The schema and stored procedure conversion, which is the part that sets your timeline Free to download and run
Adapters Hosted field level mapping with backfill and incremental sync, mapping reviewed before the first load Keeping SQL Server and Snowflake in agreement after the migration, when both stay alive Flat from $49 a month, not metered by rows
AWS DMS Managed replication instance: full load then change capture from the SQL Server transaction log Continuous replication into Snowflake with a cutover measured in seconds Per hour of replication instance, plus storage and data transfer
Azure Data Factory Pipeline orchestration with a Snowflake sink, staged through blob storage Estates already on Azure where SQL Server is Azure SQL and the network path is short Per pipeline activity run and per integration runtime hour
Fivetran Managed connector with log based change capture and schema drift handling Teams who want the pipeline to be somebody else's problem and can absorb usage based cost Consumption based on monthly active rows
Matillion Push down ELT that generates SQL executed by the Snowflake warehouse itself Heavy in-warehouse transformation after the raw landing is done Credit based, plus the Snowflake compute it drives
Airbyte Open source connector framework, self hosted or cloud, with a SQL Server source and Snowflake destination Teams who want to read and patch the connector rather than file a support ticket Free self hosted; cloud is capacity based
Qlik Replicate Log based change capture built for high volume relational replication Large regulated estates replicating many SQL Server instances at once Quoted licence, not published
Striim Streaming change capture with in flight transformation before the data lands Cases where the data has to be reshaped in motion rather than after landing Quoted, usage based
Debezium and Kafka SQL Server connector emits change events to Kafka; a sink connector writes to Snowflake Organisations that already run Kafka and want change events available to more than one consumer Free software, and you pay for the cluster and the people
Informatica IDMC Enterprise integration platform with mass ingestion and a Snowflake target Estates that already standardised on Informatica and have the governance requirement to match Consumption units, quoted per contract
COPY INTO and Snowpipe Native bulk load from staged files, with Snowpipe for continuous ingestion of new files One time moves where you can export to Parquet or CSV and downtime is acceptable Snowflake credits for warehouse time; Snowpipe bills per file plus compute

SnowConvert

Snowflake

Where it loses: Converts code, not rows. It marks CURSOR, HIERARCHYID, GEOMETRY and TABLE as unsupported and leaves them for you

Adapters

Adapters

Where it loses: We do not convert stored procedures. If your problem is 3,000 lines of T-SQL, start with SnowConvert

AWS DMS

Amazon Web Services

Where it loses: Change capture needs SQL Server Agent running, and the log truncation point does not advance until capture has read the changes

Azure Data Factory

Microsoft

Where it loses: Staging through blob storage is a step you own. Cost is easy to model and easy to under-model

Fivetran

Fivetran

Where it loses: A migration backfill is a very large month of active rows. Model the backfill separately from steady state

Matillion

Matillion

Where it loses: Push down means your Snowflake bill carries the transformation. That is efficient and it is not free

Airbyte

Airbyte

Where it loses: Self hosted means you own the runtime, the upgrades and the 3am failure

Qlik Replicate

Qlik

Where it loses: Priced for the enterprise case. Overkill for a single database move

Striim

Striim

Where it loses: Transformation in flight is powerful and harder to reason about when reconciliation fails

Debezium and Kafka

Open source

Where it loses: This is infrastructure, not a product. Do not adopt Kafka to do one migration

Informatica IDMC

Informatica

Where it loses: No public list price. Assume a procurement cycle rather than a signup

COPY INTO and Snowpipe

Snowflake

Where it loses: You own the export, the file splitting and the retries. Cheapest option and the most manual

SQL Server to Snowflake data type mapping, and what each conversion costs you

The target column is the mapping SnowConvert publishes. The last column is what that mapping does to your data, which is the part the mapping table does not carry. Read it before the first load, not after the first reconciliation meeting.

SQL Server type Snowflake target What it costs you
BIT BOOLEAN Clean. SQL Server bit holds 0, 1 or NULL and Snowflake BOOLEAN holds TRUE, FALSE or NULL. Application predicates written as = 1 need rewriting to = TRUE.
TINYINT NUMBER(38,0) The 0 to 255 range guard disappears. Add CHECK (col BETWEEN 0 AND 255) to keep it.
SMALLINT NUMBER(38,0) Same again for -32,768 to 32,767, despite the vendor table calling this one equivalent.
INT NUMBER(38,0) Arithmetic that used to overflow loudly at 2,147,483,647 now succeeds quietly. Downstream systems expecting a 32 bit integer will overflow instead, further away from the cause.
BIGINT NUMBER(38,0) Same widening, rarely a problem in practice because few values approach the 64 bit ceiling.
DECIMAL and NUMERIC NUMBER(p,s) Clean, and the one numeric family that behaves. Snowflake NUMBER allows 38 digits of precision and 37 of scale.
MONEY and SMALLMONEY NUMBER(38,4) Correct. Microsoft documents money as accurate to a ten-thousandth, which is the four decimal places this mapping preserves.
FLOAT and REAL FLOAT (64 bit) A SQL Server real widens from four bytes to eight. Nothing is lost and stored approximations start showing digits the source never displayed, which reads as a data error to anyone comparing screenshots.
DATETIME TIMESTAMP_NTZ(3) Faithful to what SQL Server stored, which is already rounded to .000, .003 or .007 seconds. Values of .999 were rolled into the next day before you started.
DATETIME2 TIMESTAMP_NTZ(7) Clean. Snowflake supports up to nine digits of fractional precision, so nothing is lost.
SMALLDATETIME TIMESTAMP_NTZ(0) Minute precision, seconds always zero. Do not read the vendor note as meaning the time of day is dropped.
DATETIMEOFFSET TIMESTAMP_TZ Correct, and only if you write TIMESTAMP_TZ explicitly. A bare TIMESTAMP resolves to TIMESTAMP_NTZ by default and the offset is gone.
UNIQUEIDENTIFIER VARCHAR(36) Sort order changes, because SQL Server does not order GUIDs by their bit pattern and a string comparison does.
ROWVERSION and TIMESTAMP BINARY(8) The bytes arrive and the behavior does not. Snowflake will not auto increment it, so the column becomes a dead snapshot. Use a real updated_at or a sequence.
VARCHAR(MAX) and NVARCHAR(MAX) VARCHAR SQL Server allows 2 GB, Snowflake caps at 128 MB. Almost always fine, and worth one query against the source to confirm before you find out during the load.
XML VARIANT Workable. You lose XML schema validation and gain semi structured querying. VARIANT is capped at 16 MB compressed.
SQL_VARIANT VARIANT Type discipline moves from the column to your queries. Anything that relied on SQL_VARIANT_PROPERTY needs rewriting.
CURSOR, HIERARCHYID, GEOMETRY, TABLE No target defined SnowConvert marks all four unsupported. HIERARCHYID usually becomes a materialised path in VARCHAR, and GEOMETRY needs re-deriving as GEOGRAPHY in WGS84 or storing as text.

The integer rows are the ones worth arguing about internally. Four distinct SQL Server types with four distinct ranges all land in the same 38 digit number, so every range check your schema performed for free is now something your application has to do, or something a CHECK constraint has to do. For the statement level equivalent of this table, see converting SQL Server data types to Snowflake, which carries the verification query for every risky row.

Eight failures that report success

Every row below is a state where the migration logs no error, the load reports success, and the row counts reconcile exactly. These are the failures that reach production, precisely because nothing catches them. The last column is the query or the control that does.

Failure What you see Cause How to catch it
Duplicates appear in a table that had a primary key for a decade Reports double count. No constraint violation is ever logged Snowflake does not enforce PRIMARY KEY or UNIQUE on standard tables. The constraint converted, loaded and is recorded as metadata that nothing checks After every load, run SELECT id, count(*) FROM t GROUP BY 1 HAVING count(*) > 1. Make it a scheduled check, not a one off
A join quietly returns fewer rows Totals drop by a few percent and every individual row you spot check looks correct Snowflake compares strings case sensitively by default. The common SQL Server installation collation, SQL_Latin1_General_CP1_CI_AS, is case insensitive, so joins on email or product code matched across case in the source and no longer do On the source, SELECT lower(col), count(DISTINCT col) FROM t GROUP BY 1 HAVING count(DISTINCT col) > 1. Every group is a join that is about to break
Time zone offsets vanish Timestamps are all present, all plausible, and several hours wrong for non-UTC records A DATETIMEOFFSET column was written to a bare TIMESTAMP. The TIMESTAMP_TYPE_MAPPING parameter defaults to TIMESTAMP_NTZ, so the offset was discarded on arrival Declare TIMESTAMP_TZ explicitly for every offset aware column. Never let a migration script emit a bare TIMESTAMP
Daily counts are off by a handful of rows at midnight Row totals match exactly, but a count grouped by day differs from the source by one or two rows per day SQL Server datetime rounds to increments of .000, .003 and .007, and Microsoft's own example shows 23:59:59.999 stored as 00:00:00.000 the following day. Those rows crossed the day boundary before the migration ran Group by day on the source and the target and diff. If the counts differ, the source is where the row moved, not your pipeline
A status column starts holding impossible values A downstream case statement falls through to its else branch for a small number of rows The column was tinyint, physically incapable of holding -1 or 500. It is now NUMBER(38,0), which accepts both, and some upstream writer had a bug the source silently prevented Recreate the guard: ALTER TABLE t ADD CONSTRAINT chk CHECK (status BETWEEN 0 AND 255). Snowflake does enforce CHECK on standard tables
Paginated exports skip and repeat rows An export that pages through ORDER BY guid returns a different set than it used to, with gaps and overlaps The GUID is now a VARCHAR ordered by Unicode code point. Microsoft documents that SQL Server does not order uniqueidentifier by bit pattern, so the two engines genuinely disagree on the sequence Page on a monotonic key or an explicit ordering column. Never page on a GUID across two engines
The source already contains truncated GUIDs A handful of GUIDs in SQL Server are valid, unique and not the value the application wrote Microsoft documents uniqueidentifier as limited to 36 characters and subject to character truncation rules, and its own example shows a longer string silently truncated on conversion with no error raised Do not assume the source is clean because it validated. Compare GUIDs against the application's own log of what it wrote, for a sample, before you trust them as keys
The reload doubles the table instead of replacing it A retried batch lands twice and the load reports success both times The pipeline appended rather than merged, and nothing on the Snowflake side rejects a duplicate primary key because nothing enforces one Land into a staging table and MERGE on the business key. Assume every batch will be replayed at least once, because eventually one will be

Six numbers that decide this migration

Every figure below was read from primary vendor documentation on 2 September 2026 and is sourced under the card. Where a vendor publishes no number, this page says so rather than inventing one.

NOT NULL and CHECK

The only constraint types a standard Snowflake table always enforces. PRIMARY KEY, UNIQUE and FOREIGN KEY are accepted, stored as metadata and not enforced. Hybrid tables do enforce them.

Snowflake SQL reference, constraints, read 2 September 2026

NUMBER(38,0)

What SMALLINT, TINYINT, INT and BIGINT all resolve to in Snowflake. The docs state the integer aliases are "synonymous with NUMBER" and always default to 38 digits of precision and zero scale.

Snowflake SQL reference, numeric data types, read 2 September 2026

cs (default)

Snowflake's default string collation is case sensitive. The usual SQL Server installation collation for a US English locale, SQL_Latin1_General_CP1_CI_AS, is case insensitive.

Snowflake collation specifications and Microsoft Learn, read 2 September 2026

TIMESTAMP_NTZ

What the TIMESTAMP_TYPE_MAPPING parameter defaults to, so a bare TIMESTAMP is time zone naive. A DATETIMEOFFSET written into one loses its offset with no error.

Snowflake SQL reference, datetime data types, read 2 September 2026

.000, .003, .007

The only millisecond values a SQL Server datetime column can hold. Microsoft documents the accuracy as "Rounded to increments of .000, .003, or .007 seconds" and advises against datetime for new work.

Microsoft Learn, datetime (Transact-SQL), read 2 September 2026

128 MB

The Snowflake VARCHAR maximum, 134,217,728 bytes, against 2 GB for a SQL Server VARCHAR(MAX). The default when no length is declared is 16,777,216.

Snowflake SQL reference, string data types, read 2 September 2026

How to migrate SQL Server to Snowflake in six steps

  1. 01

    Inventory the types before you pick a tool

    Query sys.columns joined to sys.types on the source and group by type name. You are looking for seven things: every integer type, uniqueidentifier, rowversion, datetime, datetimeoffset, the MAX string types, and anything in the unsupported list. That one query tells you more about the difficulty of this migration than any vendor assessment report, and it takes a minute to write.

  2. 02

    Run SnowConvert, then read what it produced

    It is free, it is built by Snowflake for this exact route, and it produces an assessment report you can scope from. Then open the generated DDL and compare it against the type table on this page. The integer rows and the datetimeoffset rows are the two to check first, because each produces valid DDL, loads without error, and changes what the column means.

  3. 03

    Decide what happens to every constraint you are about to lose

    This is the step that has no equivalent in a PostgreSQL migration and the one teams skip. Every primary key and unique index in the source stops being enforced the moment it lands in a standard Snowflake table. For each one, decide explicitly: rebuild it as a scheduled duplicate check, move that table to a hybrid table, or accept the risk in writing. Do not let the default be silence.

  4. 04

    Prove the data on the source, not the target

    For every text column in a unique index, group by lower() and look for collisions that the case insensitive source allowed. For every datetime column, count rows landing on a day boundary. For every MAX string column, check the maximum length against 128 MB. Each is a one line query and each prevents a class of failure that otherwise surfaces weeks after go-live.

  5. 05

    Load once, then reconcile on values rather than counts

    Do a full load into an empty database. Then compare, per table, the row count, the SUM of every numeric column, the MIN and MAX of every date column, a count grouped by day, and a hash of the business keys. Row counts alone reconcile perfectly on a migration that has dropped every time zone offset and reshuffled every GUID ordering.

  6. 06

    Switch on change capture and merge, never append

    Read changes from the SQL Server transaction log and apply them in micro batches, because Snowflake bills warehouse time and rewards batching over row by row writes. Land each batch in a staging table and MERGE on the business key. Assume every batch will be replayed at least once, since nothing in Snowflake will reject the duplicate on your behalf.

Who moves SQL Server into Snowflake, and why

Getting reporting off the transactional box

The most common reason this project gets funded. Analysts were running heavy queries against the OLTP SQL Server and someone finally measured what it cost.

Escaping a per core licence

Snowflake moves the analytical workload off SQL Server entirely, which changes the core count you are paying Microsoft for. The commercial case usually leads and the engineering follows.

Consolidating several SQL Server instances

Estates that grew by acquisition often have four or five instances with overlapping schemas. Snowflake becomes the one place they are finally comparable.

Feeding BI and a data science team from one place

Where separate extracts had drifted apart, a single landing zone makes the numbers agree again, which is worth more than the migration costs.

Keeping both systems live indefinitely

The outcome nobody plans for and most teams reach. An application, a department or an old integration keeps SQL Server alive, and the one time move becomes an ongoing sync.

Joining SQL Server data to SaaS sources

Once the warehouse exists, the ERP and CRM data usually follows within a quarter, and the mapping work you did here is the template for all of it.

Where Adapters is the wrong choice

Five jobs on this page that somebody else does better. If you are in one of these, take the other tool.

  • Converting stored procedures and T-SQL business logic. SnowConvert is built for exactly this and free to run. We do not do it and would be worse at it.
  • A pure one time lift of a very large history with no ongoing sync. Export to Parquet and use COPY INTO. That is what it is for and it will cost you less than we do.
  • Air gapped environments with no outbound network. We are a hosted service. If nothing may leave your network, this is the wrong shape of product.
  • Petabyte scale continuous replication across dozens of instances. That is the enterprise replication market and the specialists there earn their licence fee.
  • Teams who need the pipeline to also do heavy in-warehouse transformation. Land the data with us if you like, but the modelling layer belongs in dbt or Matillion.

Four questions to ask any vendor on this list

Show me your default type mapping, in writing
Any tool worth using publishes its casting rules. Then check them, because published does not mean correct. Every mapping in the table above is taken from a vendor's own documentation and several are contradicted by the documentation of the product being mapped to. Ask specifically what happens to DATETIMEOFFSET, UNIQUEIDENTIFIER and the integer types.
What do you do about constraints Snowflake will not enforce?
The honest answer is that no pipeline can enforce a primary key that the destination ignores. What a good vendor can do is tell you which keys are unprotected and offer a duplicate check after each load. If the answer is that Snowflake handles it, the vendor has not read the constraints page.
How do you reconcile, and on what?
If the answer is row counts, keep looking. Row counts reconcile perfectly on a load that dropped every time zone offset. Ask for value level checks: sums, hashes, distinct counts and a count grouped by day.
What does the backfill cost, separately from steady state?
A migration backfill is not a normal month. On row based pricing it is the largest month you will ever have, and on credit based pricing it is a spike in warehouse time. Ask the vendor to price the backfill and the first two reloads, because there will be reloads.

Questions buyers ask about SQL Server to Snowflake migration

How do I migrate data from SQL Server to Snowflake?
Convert the schema, land the rows, then rewrite the T-SQL, and treat those as three separate projects. SnowConvert handles the first and produces an assessment report. A replication tool or a staged COPY INTO handles the second. The third is hand work. The step teams skip is auditing the generated type mapping before the first load, because that is where a conversion that reports success quietly changes what your columns mean.
What is the best SQL Server to Snowflake migration tool?
SnowConvert for the schema and code conversion, because it is built by Snowflake for exactly this route and costs nothing to run. A change data capture tool for the rows when you need a cutover measured in seconds rather than a weekend. Native COPY INTO from staged files when the move is one time and downtime is acceptable. The choice matters less than whether you override the default type mapping first.
What are the main SQL Server to Snowflake migration challenges?
Three dominate. Snowflake does not enforce primary key, unique or foreign key constraints on standard tables, so integrity your schema guarded for years stops being guarded. Snowflake compares strings case sensitively while the usual SQL Server collation does not, so joins quietly return fewer rows. And every SQL Server integer type lands in the same 38 digit number, so range limits disappear.
How does SQL Server to Snowflake data type mapping work?
Most types have an obvious target and a non obvious consequence. SMALLINT, INT, BIGINT and TINYINT all become NUMBER(38,0), so the ranges stop being enforced. DATETIME becomes TIMESTAMP_NTZ(3). DATETIMEOFFSET becomes TIMESTAMP_TZ. UNIQUEIDENTIFIER becomes VARCHAR, which changes sort order. The full table further down this page gives every mapping and what each one costs you.
How much does a SQL Server to Snowflake migration cost?
The conversion tooling is usually free and the compute during the backfill is not. SnowConvert is free to run. What you pay for is the Snowflake credits burned loading and re-loading history while you iterate on the mapping, plus engineer time converting stored procedures. Budget for at least three full reloads, because the first two will be wrong in ways row counts do not reveal.
Can you convert SQL Server to Snowflake automatically?
Tables and data convert automatically. Stored procedures, functions, triggers and anything relying on T-SQL specific behavior do not. Snowflake has no direct equivalent for CURSOR, HIERARCHYID, GEOMETRY or the TABLE type, and SnowConvert marks all four as unsupported in its own translation reference. Budget hand conversion for every stored routine and for every query the application sends.
What data types do not convert from SQL Server to Snowflake?
SnowConvert lists CURSOR, HIERARCHYID, GEOMETRY and TABLE as not supported by Snowflake, with no target type defined. ROWVERSION converts to BINARY(8) but Snowflake does not reproduce its auto increment behavior, so the column becomes a dead byte string. NVARCHAR(MAX) and NTEXT have no exact equivalent because Snowflake caps a VARCHAR at 128 MB while SQL Server allows 2 GB.
Does Snowflake enforce primary keys and unique constraints?
No, not on standard tables. Snowflake accepts the constraint definitions and records them as metadata, then does not enforce PRIMARY KEY, UNIQUE or FOREIGN KEY. Only NOT NULL and CHECK are always enforced. Hybrid tables do enforce them. This is the single biggest behavioral difference in the migration, and it produces no error at any point.
What is the difference between SQL Server and Snowflake SQL?
Beyond dialect, two differences change results. Snowflake compares strings case sensitively by default, while the common SQL Server installation collation is case insensitive, so equality and joins behave differently. And Snowflake has one 38 digit numeric type behind every integer alias, so arithmetic that overflowed loudly in SQL Server now succeeds silently.
How do I connect SQL Server to Snowflake for ongoing sync?
Read changes from the SQL Server transaction log with change data capture, then apply them to Snowflake in micro batches rather than row by row, because Snowflake charges for warehouse time and rewards batching. Point the pipeline at a staging table and merge, so a replayed batch does not duplicate rows given that Snowflake will not reject the duplicate for you.

For the people cost that dominates every migration program, read what a data migration really costs. For the difference between moving data once and moving it continuously, see ETL vs ELT, and for the wider vendor landscape, the best data integration tools. The same destination from an application database instead is covered in Postgres to Snowflake migration tools, and from the other commercial engine, where an Oracle entitlement sits behind Snowflake's own connector, in Oracle to Snowflake migration tools.

Move SQL Server into Snowflake once, then keep the two in agreement

Map the fields once, run the backfill, then let the same mapping run incrementally with retries, alerts and per-record logs. From $49 a month, not metered by rows.

Try the live demo

No credit card required.