Qlik .qvf / .qvw apps and .qvs includes parsed structurally. Converted to Snowflake SQL with CTEs, MERGE statements, and COPY INTO. Full lineage, validated parity.
Deterministic parsers read the estate and emit native Snowflake code — not Qlik apps re-pointed at a cloud warehouse.
Qlik → MigryX parser → SQL + Snowpark + Tasks
Deterministic parseAI optionalAI is an optional add-on, off by default — the conversion runs end to end without it, air-gapped if your estate requires it.
Qlik mapping tables and JOIN/RESIDENT loads run inside a single-node engine. Snowflake pushes joins, filters, and aggregations into its massively parallel SQL engine. Lookups that reload an app finish as SQL on the warehouse.
STORE ... INTO *.qvd writes a proprietary file. Snowflake COPY INTO and MERGE load from stages at warehouse speed. MigryX turns each STORE into a table write so the QVD tree is not rehosted.
Qlik script variables manage environment-specific paths and thresholds inside the app. Snowflake session variables, account parameters, and Snowpark configuration provide native, auditable environment management with role-based access control.
A Qlik load script with a mapping load and conditional segmentation — converted to a Snowflake CTE pipeline with MERGE for upsert logic. No Qlik engine, no QVD hop.
// App: Customer_Revenue_Update
SET vMinAmount = 1000;
Tiers:
MAPPING LOAD CUST_ID, TIER_CODE
FROM [lib://QVD/customer_master.qvd] (qvd);
Txns:
LOAD
CUST_ID,
AMOUNT,
TOTAL_SPEND,
ApplyMap('Tiers', CUST_ID, 'Standard') as SEGMENT
FROM [lib://QVD/transactions.qvd] (qvd)
WHERE AMOUNT > $(vMinAmount);
Seg:
LOAD
if(TOTAL_SPEND > 50000, 'Platinum',
if(TOTAL_SPEND > 10000, 'Gold', SEGMENT)) as SEGMENT,
Sum(AMOUNT) as SEGMENT_REVENUE,
Count(CUST_ID) as CUSTOMER_COUNT
RESIDENT Txns
GROUP BY SEGMENT, TOTAL_SPEND;
STORE Seg INTO [lib://QVD/customer_segments.qvd] (qvd);
-- ApplyMap + RESIDENT → Snowflake SQL
WITH segmented AS (
SELECT
t.cust_id,
CASE
WHEN t.total_spend > 50000 THEN 'Platinum'
WHEN t.total_spend > 10000 THEN 'Gold'
ELSE COALESCE(c.tier_code, 'Standard')
END AS segment,
t.amount
FROM customer_transactions t
LEFT JOIN customer_master c
ON t.cust_id = c.cust_id
WHERE t.amount > 1000
),
agg AS (
SELECT
segment,
SUM(amount) AS segment_revenue,
COUNT(*) AS customer_count
FROM segmented
GROUP BY segment
)
MERGE INTO customer_segments tgt
USING agg src
ON tgt.segment = src.segment
WHEN MATCHED THEN UPDATE SET
tgt.segment_revenue = src.segment_revenue,
tgt.customer_count = src.customer_count
WHEN NOT MATCHED THEN INSERT
(segment, segment_revenue, customer_count)
VALUES (src.segment, src.segment_revenue,
src.customer_count);
ApplyMap becomes LEFT JOIN + COALESCE. Nested if() becomes CASE WHEN. STORE to QVD becomes MERGE instead of another proprietary file.
| Qlik Construct | Snowflake Equivalent | Notes |
|---|---|---|
| MAPPING + ApplyMap | LEFT JOIN + COALESCE | Default values become explicit |
| JOIN / LEFT JOIN | JOIN | Join keys preserved |
| RESIDENT + GROUP BY | GROUP BY + aggregates | SUM, COUNT, AVG, MIN, MAX preserved |
| WHERE / if() | WHERE / CASE WHEN | All predicate expressions preserved |
| CONCATENATE | UNION ALL | Column alignment reported |
| Crosstable / Generic | UNPIVOT / PIVOT | Attribute-value reshapes kept |
| LOAD FROM file | COPY INTO from stage | Bulk load from S3/Azure/GCS |
| STORE ... INTO .qvd | Table write / MERGE | QVD layer replaced |
| SET / LET | Session variables / params | Environment configs externalized |
| $(Include=) / .qvs | Stored procedure | Reusable scripts stay callable |
| Reload task chain | Snowflake Task | App chaining → task DAG |
| Section Access | RBAC + row access policies | Reduction rules extracted for review |
Data Matching compares Qlik load-script output against Snowflake output — row by row, column by column. Send a .qvs or a .qvf and we prove the rewrite before cutover.
See how Data Matching works →The apps that own the load script. We unpack the script, variables, and lib connects. A running Qlik engine is not required.
Shared calendar, mapping, and connection scripts referenced by $(Include=...). Those stay reusable procedures on Snowflake.
Enough rows to prove parity. We do not convert the QVD format; we convert the STORE/LOAD statements that produce and consume it.