A common ask from teams evaluating Sigma is migrating their Qlik Sense footprint — usually to take advantage of all the amazing things Sigma offers. The conversion itself can be a blocker — and the part this QuickStart automates.

The usual Qlik-to-Sigma migration loop is rebuild-the-app-by-hand, rewrite every master measure and Set Analysis expression as a Sigma formula, recreate each sheet's visualizations, line the layout up against the source, then eyeball the numbers and hope nothing drifted in the translation. Done on a single app it's tedious. Across a whole tenant with dozens of apps reading from shared spaces, it's the reason migration projects slip.

This QuickStart walks through a Claude Code skill called qlik-to-sigma that automates the loop.

Point it at a Qlik Cloud app; it discovers the in-memory data model and every sheet via qlik-cli, translates the master measures, dimensions, and Set Analysis expressions into Sigma formulas, builds a Sigma data model from the warehouse tables the app's LOAD script reads, mirrors each sheet's layout on Sigma's grid, and runs a verification pass against the source warehouse. It surfaces a punch list of anything it couldn't auto-translate — instead of silently producing a broken workbook.

For the demonstration, we'll run the skill end-to-end against a Qlik app called Exec Overview (Qlik) whose LOAD script reads from a six-table retail star — one fact and five dimensions. You'll see the discovery artifacts each phase produces, the converter's breakdown of how each Qlik expression mapped to a Sigma formula, the parity report against the live warehouse, and the resulting Sigma data model and workbook landed in your org — along with the gap list of items to hand-polish.

What else this enables

A pure lift-and-shift is the floor, not the ceiling. The same skill family supports three follow-on moves that turn a migration into an upgrade:

Target Audience

Sigma SEs, technical CSMs, and migration partners running Qlik-to-Sigma conversions — or scoping a batch migration with the companion qlik-assessment skill.

Prerequisites

Sigma Free Trial

Footer

qlik-to-sigma is one of two skills that ship together as a single repo (cloned in the next section). Most of this QuickStart focuses on the converter — but knowing where the assessment skill fits saves dead ends later when scoping a batch migration.

Skill

Role

When to reach for it

qlik-assessment

Scoping

Auditing a Qlik Cloud tenant before committing to a conversion plan. Emits a per-app complexity readout (master-measure expression convertibility, chart-type coverage, Set Analysis / Section Access flags, data model size), reload health, and a value/cost-ranked migration shortlist that qlik-to-sigma can consume.

qlik-to-sigma

Conversion

The subject of this QuickStart. Converts a single Qlik app (or a batch via shortlist) to a Sigma data model and matching workbook with verified data parity.

Here's how the two skills connect in a full migration — qlik-assessment hands the converter a ranked shortlist, and qlik-to-sigma produces the Sigma workbooks with a verified parity report:

Which skill for your situation

Not every migration needs both skills. Use the table below to map your scenario to the smallest set that fits.

In this QuickStart we're in the first row — one Qlik app whose LOAD script reads from warehouse tables that we'll land in Snowflake — then run qlik-to-sigma.

Your situation

Skill(s) to use

1 app, LOAD script reads from your warehouse

qlik-to-sigma

1 app, LOAD script reads from local files or in-memory sources

Land the data in your warehouse first (covered in Prepare the Demo Data), then qlik-to-sigma

10+ apps (any data source)

qlik-assessmentqlik-to-sigma in batch mode

Auditing Qlik sprawl without converting yet

qlik-assessment only

Footer

First we need to clone the skill's GitHub repository, install qlik-cli, configure it against your Qlik tenant, then capture your Sigma credentials.

The two skills live in sigmacomputing/quickstarts-public under qlik-migration-skills/.

From a terminal, run each command below one at a time so you can confirm each step before moving on.

Step 1: Create a local folder for the clone
We'll clone into this folder in the next step.

mkdir -p ~/quickstarts-public

Step 2: Move into the new folder so the next command runs in the right working directory.

cd ~/quickstarts-public

Step 3: Clone the repo without pulling any files yet
The --sparse flag tells Git you'll choose which folders to fill in next. The trailing . clones into the current folder.

git clone --filter=blob:none --sparse https://github.com/sigmacomputing/quickstarts-public.git .

Step 4: Fill in only the qlik-migration-skills folder
Every other QuickStart asset in the repo stays empty on disk.

git sparse-checkout set qlik-migration-skills

Step 5: Symlink qlik-to-sigma into the Claude skills folder
This lets Claude Code invoke qlik-to-sigma as a skill.

ln -s ~/quickstarts-public/qlik-migration-skills/qlik-to-sigma ~/.claude/skills/qlik-to-sigma

Step 6: Symlink qlik-assessment
Used to scope a Qlik tenant before conversion.

ln -s ~/quickstarts-public/qlik-migration-skills/qlik-assessment ~/.claude/skills/qlik-assessment

Steps 5 and 6 should return with no error.

divider

Step 7: Install qlik-cli

The Qlik skill talks to your Qlik Cloud tenant through qlik-cli — the official command-line tool that wraps both Qlik's REST API and the Engine API. The skill needs both: REST to discover apps and read metadata, Engine to read sheet/chart definitions and the LOAD script.

On macOS or Linux, tap Qlik's Homebrew repository:

brew tap qlik-oss/taps

After this finishes, trust the tap (recent Homebrew versions require this for non-core taps before they'll install from them):

brew trust qlik-oss/taps

Then install the formula:

brew install qlik-cli

Confirm qlik-cli is on your PATH:

qlik version

You should see output like version X.Y.Z.

divider

Step 8: Configure a qlik-cli context against your tenant

The skill authenticates with an OAuth M2M client (configured by your tenant admin under Administration > Integrations > OAuth clients). Your admin enables the Trusted consent method on the client, then shares the client ID and secret with you.

Create a qlik-cli context that uses those credentials. Substitute your tenant URL, client ID, and client secret:

qlik context create qlik-demo \
  --server https://<your-tenant>.us.qlikcloud.com \
  --oauth-client-id <client-id> \
  --oauth-client-secret <client-secret>

Activate the context and verify auth works:

qlik context use qlik-demo
qlik app ls --limit 5

You should see a JSON list of apps your OAuth client can access:

divider

Step 9: Capture your Sigma API credentials.
This script prompts for SIGMA_BASE_URL, SIGMA_CLIENT_ID, and SIGMA_CLIENT_SECRET and writes them into Claude's settings.

Run once per machine.

If you don't already have credentials, see Configure API credentials in Sigma — the skill needs API access credentials, not embed.

ruby ~/.claude/skills/qlik-to-sigma/scripts/setup.rb

divider

Step 10: Verify Claude Code can invoke the skill.
Type claude in your terminal to start Claude Code, then invoke the skill:

claude
/qlik-to-sigma

Claude should start reading the reference files and ask what app you want to convert.

Pause at that prompt — we'll hand it everything in one shot via the kickoff prompt in Run the Conversion:

Footer

The Qlik app we're migrating runs a LOAD script that reads from a six-table retail star — one fact (ORDER_FACT) joined LEFT_OUTER to five dimensions (CUSTOMER_DIM, PRODUCT_DIM, STORE_DIM, DATE_DIM, PROMO_DIM). For the migration to land in Sigma cleanly, the same six tables need to exist in a connection your Sigma org can reach. Approximate row counts: 681 / 25 / 25 / 15 / 1,096 / 23.

Data prep has two halves:

  1. Qlik side — nothing to do here for this QuickStart. We've already exported the six tables from the source warehouse and hosted them as CSVs in Amazon S3. The Snowflake COPY INTO statements below read from S3 directly — no local download needed.
  2. Sigma side (this section) — the same data needs to live in a Snowflake schema your Sigma connection can read. We'll create one.
USE ROLE ACCOUNTADMIN;
USE WAREHOUSE COMPUTE_WH;

CREATE DATABASE IF NOT EXISTS QUICKSTARTS;
CREATE SCHEMA  IF NOT EXISTS QUICKSTARTS.TS_RETAIL_ANALYTICS;
USE SCHEMA QUICKSTARTS.TS_RETAIL_ANALYTICS;

CREATE OR REPLACE FILE FORMAT csv_format
  TYPE = CSV
  FIELD_DELIMITER = ','
  SKIP_HEADER = 1
  FIELD_OPTIONALLY_ENCLOSED_BY = '"'
  NULL_IF = ('', 'NULL')
  EMPTY_FIELD_AS_NULL = TRUE;

CREATE OR REPLACE STAGE ts_retail_stage
  URL = 's3://sigma-quickstarts-main/thoughtspot/'
  FILE_FORMAT = csv_format;

-- Fact: ORDER_FACT (681 rows, joins to all 5 dims via *_KEY columns).
CREATE OR REPLACE TABLE ORDER_FACT (
  ORDER_ID           VARCHAR,
  ORDER_LINE         NUMBER(38,0),
  CUSTOMER_KEY       NUMBER(38,0),
  PRODUCT_KEY        NUMBER(38,0),
  ORDER_STORE_KEY    NUMBER(38,0),
  SHIP_STORE_KEY     NUMBER(38,0),
  PROMO_KEY          NUMBER(38,0),
  ORDER_DATE_KEY     NUMBER(38,0),
  SHIP_DATE_KEY      NUMBER(38,0),
  RETURN_DATE_KEY    NUMBER(38,0),
  ORDER_CHANNEL      VARCHAR,
  SHIP_METHOD        VARCHAR,
  ORDER_STATUS       VARCHAR,
  QUANTITY_ORDERED   NUMBER(38,0),
  QUANTITY_RETURNED  NUMBER(38,0),
  UNIT_PRICE         NUMBER(38,2),
  UNIT_COST          NUMBER(38,2),
  DISCOUNT_AMOUNT    NUMBER(38,2),
  SHIPPING_AMOUNT    NUMBER(38,2),
  TAX_AMOUNT         NUMBER(38,2),
  GROSS_REVENUE      NUMBER(38,2),
  NET_REVENUE        NUMBER(38,2),
  GROSS_PROFIT       NUMBER(38,2),
  NET_PROFIT         NUMBER(38,2),
  IS_FIRST_ORDER     NUMBER(1,0),
  IS_RETURNED        NUMBER(1,0),
  IS_CANCELLED       NUMBER(1,0),
  DAYS_TO_SHIP       NUMBER(38,0)
);

CREATE OR REPLACE TABLE CUSTOMER_DIM (
  CUSTOMER_KEY          NUMBER(38,0),
  CUSTOMER_ID           VARCHAR,
  FIRST_NAME            VARCHAR,
  LAST_NAME             VARCHAR,
  EMAIL                 VARCHAR,
  PHONE                 VARCHAR,
  CITY                  VARCHAR,
  STATE                 VARCHAR,
  ZIP_CODE              VARCHAR,
  REGION                VARCHAR,
  CUSTOMER_SEGMENT      VARCHAR,
  LOYALTY_TIER          VARCHAR,
  ACQUISITION_CHANNEL   VARCHAR,
  FIRST_ORDER_DATE      DATE,
  IS_ACTIVE             NUMBER(1,0),
  IS_EMAIL_OPT_IN       NUMBER(1,0),
  LIFETIME_ORDER_COUNT  NUMBER(38,0),
  LIFETIME_REVENUE      NUMBER(38,2)
);

CREATE OR REPLACE TABLE PRODUCT_DIM (
  PRODUCT_KEY         NUMBER(38,0),
  PRODUCT_ID          VARCHAR,
  PRODUCT_NAME        VARCHAR,
  CATEGORY            VARCHAR,
  SUBCATEGORY         VARCHAR,
  BRAND               VARCHAR,
  UNIT_COST           NUMBER(38,2),
  UNIT_PRICE          NUMBER(38,2),
  WEIGHT_LBS          NUMBER(38,2),
  IS_ACTIVE           NUMBER(1,0),
  IS_PRIVATE_LABEL    NUMBER(1,0),
  IS_SEASONAL         NUMBER(1,0),
  LAUNCH_DATE         DATE,
  DISCONTINUE_DATE    DATE,
  "Product_Key/Name"  VARCHAR
);

CREATE OR REPLACE TABLE STORE_DIM (
  STORE_KEY          NUMBER(38,0),
  STORE_ID           VARCHAR,
  STORE_NAME         VARCHAR,
  STORE_TYPE         VARCHAR,
  CITY               VARCHAR,
  STATE              VARCHAR,
  REGION             VARCHAR,
  DISTRICT           VARCHAR,
  SQUARE_FOOTAGE     NUMBER(38,0),
  OPEN_DATE          DATE,
  CLOSE_DATE         DATE,
  IS_ACTIVE          NUMBER(1,0),
  HAS_CAFE           NUMBER(1,0),
  HAS_CURBSIDE       NUMBER(1,0),
  MANAGER_NAME       VARCHAR,
  STORE_PHONE        VARCHAR,
  ANNUAL_LEASE_COST  NUMBER(38,2)
);

CREATE OR REPLACE TABLE DATE_DIM (
  DATE_KEY        NUMBER(38,0),
  FULL_DATE       DATE,
  DAY_OF_WEEK     VARCHAR,
  DAY_OF_MONTH    NUMBER(38,0),
  WEEK_OF_YEAR    NUMBER(38,0),
  MONTH_NUMBER    NUMBER(38,0),
  MONTH_NAME      VARCHAR,
  QUARTER         NUMBER(38,0),
  "YEAR"          NUMBER(38,0),
  IS_WEEKEND      NUMBER(1,0),
  IS_HOLIDAY      NUMBER(1,0),
  FISCAL_PERIOD   VARCHAR
);

CREATE OR REPLACE TABLE PROMO_DIM (
  PROMO_KEY          NUMBER(38,0),
  PROMO_ID           VARCHAR,
  PROMO_NAME         VARCHAR,
  PROMO_TYPE         VARCHAR,
  CHANNEL            VARCHAR,
  DISCOUNT_PCT       NUMBER(38,2),
  START_DATE         DATE,
  END_DATE           DATE,
  MIN_ORDER_AMOUNT   NUMBER(38,2),
  IS_STACKABLE       NUMBER(1,0),
  TARGET_SEGMENT     VARCHAR,
  PROMO_COST         NUMBER(38,2)
);

COPY INTO ORDER_FACT    FROM @ts_retail_stage/ORDER_FACT.csv    ON_ERROR = ABORT_STATEMENT;
COPY INTO CUSTOMER_DIM  FROM @ts_retail_stage/CUSTOMER_DIM.csv  ON_ERROR = ABORT_STATEMENT;
COPY INTO PRODUCT_DIM   FROM @ts_retail_stage/PRODUCT_DIM.csv   ON_ERROR = ABORT_STATEMENT;
COPY INTO STORE_DIM     FROM @ts_retail_stage/STORE_DIM.csv     ON_ERROR = ABORT_STATEMENT;
COPY INTO DATE_DIM      FROM @ts_retail_stage/DATE_DIM.csv      ON_ERROR = ABORT_STATEMENT;
COPY INTO PROMO_DIM     FROM @ts_retail_stage/PROMO_DIM.csv     ON_ERROR = ABORT_STATEMENT;

-- Grant Sigma's service role visibility on the schema and its tables.
GRANT USAGE  ON DATABASE QUICKSTARTS                                    TO ROLE SIGMA_SERVICE_ROLE;
GRANT USAGE  ON SCHEMA   QUICKSTARTS.TS_RETAIL_ANALYTICS                TO ROLE SIGMA_SERVICE_ROLE;
GRANT SELECT ON ALL    TABLES IN SCHEMA QUICKSTARTS.TS_RETAIL_ANALYTICS TO ROLE SIGMA_SERVICE_ROLE;
GRANT SELECT ON FUTURE TABLES IN SCHEMA QUICKSTARTS.TS_RETAIL_ANALYTICS TO ROLE SIGMA_SERVICE_ROLE;

-- Sanity-check row counts. Expected: 681 / 25 / 25 / 15 / 1096 / 23.
SELECT 'ORDER_FACT'   AS TABLE_NAME, COUNT(*) AS ROW_COUNT FROM ORDER_FACT   UNION ALL
SELECT 'CUSTOMER_DIM', COUNT(*) FROM CUSTOMER_DIM UNION ALL
SELECT 'PRODUCT_DIM',  COUNT(*) FROM PRODUCT_DIM  UNION ALL
SELECT 'STORE_DIM',    COUNT(*) FROM STORE_DIM    UNION ALL
SELECT 'DATE_DIM',     COUNT(*) FROM DATE_DIM     UNION ALL
SELECT 'PROMO_DIM',    COUNT(*) FROM PROMO_DIM;

-- Parity baseline ($108,797.85 Net Revenue across all orders).
SELECT TO_CHAR(SUM(NET_REVENUE), '$999,999,999.99') AS TOTAL_NET_REVENUE
FROM ORDER_FACT;

If the load completes cleanly, the row-count check returns 681 / 25 / 25 / 15 / 1096 / 23 and the Net Revenue check returns $108,797.85. Any mismatch means either a COPY partial-load error (check Snowflake's load history) or a different S3 file than expected.

Footer

The converter needs a Sigma folder to land the new data model and workbook in. The skill will ask for the folder's UUID — it will be easier to have it ready before you return to the Claude prompt that's still paused after the skill loaded.

To keep this simple, we will use a plain folder and not a workspace.

Step 1: Create (or pick) a folder in Sigma.
Open your Sigma org, navigate to where you want the migrated workbook to live, and create a folder for it. Something like:

Qlik Migration Demo

Step 2: Grab the folder ID.
Open the folder. The ID is the last segment of the URL — a short alphanumeric string, 21 characters. Copy it from the address bar and keep it on the clipboard for the next section.

Footer

The skill can run interactively, asking for the Qlik app, warehouse, and Sigma destination one at a time. For a known target — like ours — it's faster to give Claude the entire job in one message. The skill recognizes a structured kickoff prompt and assembles the migrate-qlik.rb command directly, going straight from "go" through discover → convert → data model → workbook build → layout → parity.

Return to the terminal where Claude is paused, and choose Chat about this.

Paste the block below. Substitute your own values where the placeholders are:

Run /qlik-to-sigma on the following. Use migrate-qlik.rb end-to-end and stop only if a hard gate fails.

Qlik
- Context: qlik-demo
- App ID: <your-qlik-app-uuid>

Warehouse (Snowflake)
- Database: QUICKSTARTS
- Schema: TS_RETAIL_ANALYTICS

Sigma
- SIGMA_API_TOKEN = mint from ~/.sigma-migration/env
- Connection ID: <your-snowflake-connection-id>
- Folder ID: <your-folder-id>

Options
- Name prefix: Qlik Retail Analytics
- Auto-approve mid-pipeline questions: yes
- Parity: tolerate row-count drift between Qlik and the warehouse snapshot — this QuickStart uses a frozen CSV copy of the source. Report the delta with a row-level diff, but treat warehouse-snapshot staleness as a soft fail (not a gate-red).

Don't declare GREEN until the parity gate passes (or the tolerance above applies) and the visual-QA loop passes.

Claude reads the block, mints a fresh Sigma token from ~/.sigma-migration/env, assembles the migrate-qlik.rb command with the right flags, and runs it end-to-end. The rest of the run is hands-off until a gate or decision point.

Footer

When the migration completes, Claude prints a final summary covering the whole pipeline — every phase's result, the visual-QA outcome, the hard-gate verdict, and the URLs of the new Sigma data model and workbook:

The summary walks through six phases plus a visual-QA pass:

Open the new workbook in Sigma to see the migrated dashboard:

Open the data model to see how the converter wired up the joins and metrics:

Hand-polish items the skill flags rather than silently working around:

Footer

A single app is the easy case. Real migrations involve Qlik tenants with dozens or hundreds of apps reading from shared spaces — and migrating them one-by-one through the converter loses the leverage of doing the planning work once. That's where the companion qlik-assessment skill comes in.

Point qlik-assessment at a Qlik tenant and it inventories every app, space, and user, scoring each app on:

The output is a Sigma-branded readout.html you can share with stakeholders, plus a ranked migration shortlist sorted by value / (1 + cost) — the cheapest, highest-value apps to convert first, with tag pills like migrate-first, easy-win, needs-review, and retire.

The shortlist becomes input to a batch conversion planqlik-assessment groups apps that share warehouse tables so one Sigma data model can serve a whole family of workbooks instead of producing N near-duplicate DMs. qlik-to-sigma consumes that plan in batch mode and runs the conversions concurrently.

Typical flow for a real migration engagement:

  1. Run qlik-assessment against the target tenant; review the shortlist with stakeholders.
  2. Pick the top N apps to convert first — or drop the cold ones entirely.
  3. Hand the batch plan to qlik-to-sigma and let it work through them.
  4. Spot-check each output; file the inevitable gap items upstream.

Footer

The following is a "grab bag" of things that might come up during real conversions, with the fix for each.

Footer

What you built is less a single conversion and more a repeatable migration path. The skill took a Qlik Sense app — LOAD script, master measures, sheet layout, Set Analysis expressions — and produced a Sigma data model, a workbook, and a parity report against the live warehouse, all from a single structured prompt. No one rebuilt the dashboard by hand, and the parity numbers are evidence rather than hope.

The patterns worth carrying into your next migration:

A first-pass conversion produces a working starting point and a documented punch list, not a hand-polished workbook. The polish loop is short, and you know exactly what to look at. That's the migration approach you can scale across an entire Qlik tenant.

Additional Resource Links

Blog
Community
Help Center
QuickStarts

Be sure to check out all the latest developments at Sigma's First Friday Feature page!

Footer