This guide covers the key differences between Snowflake and DuckDB SQL dialects and provides practical advice for migrating your Snowflake transformations to DuckDB in Keboola.
SQLGlot can automatically convert approximately 85% of Snowflake SQL syntax to DuckDB. However, some constructs require manual adjustment. The sections below cover the most common differences you will encounter.
You can also use the Kai AI assistant in Keboola to help with migration.
Keboola provides an experimental Transformation Migration component (keboola.app-transformation-migration) that automates
the migration of Snowflake transformations to DuckDB. The component handles SQL dialect translation, preserves input/output
table mappings, and creates new DuckDB transformation configurations automatically.
Important: The automatic migration is not 100% accurate. The success rate depends on the complexity of your SQL, data types, and Snowflake-specific features used. Expect that roughly 25% of migrated transformations will require manual adjustments — for example, fixing case sensitivity issues, replacing unsupported functions, or adjusting data type casts. Always review and test the migrated configurations before using them in production.
In your Keboola project, go to Components and search for Transformation Migration. Create a new configuration. Set the following parameters:
default).Snowflake.DuckDB.%s as a placeholder for the original name
(e.g., %s keeps the same name, %s_duckdb appends a suffix).
Click Load Transformations to populate the list of available Snowflake transformations. Select one or more transformations you want to migrate to DuckDB.

After selecting the transformations, click Save and then Run Component.

Once the job completes, review the migration summary in the job detail. The logs show which transformations were migrated successfully and provide links to the newly created DuckDB configurations.

Open the newly created DuckDB transformation. The component preserves all input/output table mappings and runtime settings. Review the SQL code carefully — some queries may need manual adjustments due to syntax differences between Snowflake and DuckDB (see the sections below for common differences).

This is one of the most critical differences when migrating.
Snowflake:
MyTable becomes MYTABLE)."MyTable" and "MYTABLE" are different tables).DuckDB table names:
MyTable becomes mytable)."MyTable" references exactly MyTable).DuckDB column names:
SELECT columnName and SELECT ColumnName refer to different columns).Migration tip: Use consistent lowercase naming in DuckDB:
-- Recommended: use lowercase names
CREATE TABLE mytable AS SELECT ...;| Snowflake | DuckDB | Notes |
|---|---|---|
VARIANT |
JSON or VARCHAR |
Semi-structured data |
ARRAY |
LIST |
Native arrays |
OBJECT |
STRUCT or JSON |
Nested objects |
INTEGER |
INTEGER |
Same |
VARCHAR |
VARCHAR |
Same |
TIMESTAMP |
TIMESTAMP |
Same |
FLOAT |
FLOAT |
Same |
BOOLEAN |
BOOLEAN |
Same |
DATE |
DATE |
Same |
Snowflake supports the QUALIFY clause for filtering window function results. DuckDB does not support QUALIFY;
use a subquery with WHERE instead.
-- Snowflake
SELECT * FROM orders
QUALIFY ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) = 1;
-- DuckDB
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) AS rn
FROM orders
) WHERE rn = 1;-- Snowflake
SELECT NVL(column_a, 'default') FROM my_table;
-- DuckDB
SELECT COALESCE(column_a, 'default') FROM my_table;-- Snowflake
SELECT IFF(status = 'active', 'yes', 'no') FROM users;
-- DuckDB
SELECT CASE WHEN status = 'active' THEN 'yes' ELSE 'no' END FROM users;-- Snowflake
SELECT DATEADD(day, 7, order_date) FROM orders;
-- DuckDB
SELECT order_date + INTERVAL '7 days' FROM orders;-- Snowflake
SELECT DATEDIFF(day, start_date, end_date) FROM projects;
-- DuckDB
SELECT date_diff('day', start_date, end_date) FROM projects;-- Snowflake
SELECT department, LISTAGG(employee_name, ', ') WITHIN GROUP (ORDER BY employee_name)
FROM employees GROUP BY department;
-- DuckDB
SELECT department, STRING_AGG(employee_name, ', ')
FROM employees GROUP BY department;The following functions have the same syntax in both Snowflake and DuckDB:
SUBSTRING(str, start, len)POSITION('x' IN str)CONCAT(a, b) — both handle NULL gracefullya || b — both return NULL if any input is NULLLIMIT nFETCH FIRST n ROWSCOALESCE(a, b, c)CAST(value AS type)Same in both:
-- Basic table creation
CREATE TABLE customers (id INT, name VARCHAR);
-- Primary keys
CREATE TABLE customers (id INT PRIMARY KEY, name VARCHAR);
-- Temporary tables
CREATE TEMP TABLE temp_data (id INT);
CREATE TEMPORARY TABLE temp_data (id INT);
-- CREATE TABLE AS SELECT (CTAS)
CREATE TABLE new_table AS SELECT * FROM old_table;
-- CREATE OR REPLACE
CREATE OR REPLACE TABLE customers AS SELECT * FROM source;
-- IF NOT EXISTS
CREATE TABLE IF NOT EXISTS customers (id INT);Key differences:
-- Snowflake only --- not supported in DuckDB
CREATE TRANSIENT TABLE staging_data (id INT, value VARCHAR);DuckDB does not have a TRANSIENT keyword. Use regular or TEMP tables instead.
temp.main schema (you cannot specify a different schema).In DuckDB, a temporary table can have the same name as a regular table. The temporary table takes priority.
To access the regular table explicitly, use its fully qualified name: memory.main.table_name.
| Category | Snowflake | DuckDB |
|---|---|---|
| Window functions | QUALIFY |
ROW_NUMBER() + WHERE |
| Null handling | NVL(a, b) |
COALESCE(a, b) |
| Conditionals | IFF(cond, a, b) |
CASE WHEN cond THEN a ELSE b END |
| Date math | DATEADD(unit, n, date) |
date + INTERVAL 'n unit' |
| Date diff | DATEDIFF(unit, d1, d2) |
date_diff('unit', d1, d2) |
| String aggregation | LISTAGG(...) WITHIN GROUP |
STRING_AGG(...) |
| Temp tables | CREATE TEMPORARY TABLE |
CREATE TEMP TABLE (same) |
| Transient tables | CREATE TRANSIENT TABLE |
Not supported |
GROUP BY ALL can help resolve alias-related issues.CAST() calls to avoid type errors with functions like SUM() or AVG().For local development, DuckDB provides a Snowflake extension that lets you attach data from Snowflake and work with it using DuckDB syntax. This can be useful for testing migration queries locally before deploying them in Keboola.