A common ask from teams evaluating Sigma is migrating their Metabase 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 Metabase-to-Sigma migration loop is rebuild-the-models-by-hand, rewrite every MBQL aggregation and expression as a Sigma formula, recreate each dashboard's cards and layout, then eyeball the numbers against the source and hope nothing drifted in the translation. Done on a single dashboard it's tedious. Across a real Metabase estate — typically hundreds of cards reading from a handful of shared models — it's the reason migration projects slip.
This QuickStart walks through a Claude Code skill called metabase-to-sigma that automates the loop.
Point it at a Metabase dashboard; it discovers the dashboard's cards, the models and questions they reference, and the database metadata behind them over the Metabase REST API. It translates each card's MBQL expression (or native SQL) into a Sigma formula, builds a Sigma data model from the warehouse tables the models point at, mirrors each dashboard's layout on Sigma's grid, and runs a row-level parity pass against the live warehouse. It surfaces a punch list of anything it couldn't auto-translate — instead of silently producing a broken workbook.
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:
For the demonstration, we'll convert a small Metabase dashboard called Commerce Dashboard — four cards (a revenue scalar, orders-by-month line, revenue-by-category bar, and a top-10-products table) built against an e-commerce schema (ORDERS + PRODUCTS) extracted from Metabase's Sample Database and loaded into Snowflake. You'll see the discovery artifacts each phase produces, the converter's breakdown of how each MBQL 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.

Sigma SEs, technical CSMs, and migration partners running Metabase-to-Sigma conversions — or scoping a batch migration with the companion metabase-assessment skill.
Claude Code installed (CLI or desktop).Python 3.10 or newer. macOS's stock system Python is typically 3.9 — older than the skill needs. If python3 --version reports anything below 3.10, install a newer interpreter via Homebrew (brew install python@3.12) or python.org.Node.js (any recent LTS) for the converter (converter/: npm install once during the run). The skill also uses a separate MCP server, sigma-data-model-mcp, cloned + built (npm install && npm run build) into ~/Desktop/sigma-data-model-mcp. The skill prompts you to install it mid-conversion — no upfront work needed.
metabase-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 avoids dead ends later when scoping a batch migration.
Skill | Role | When to reach for it |
| Scoping | Auditing a Metabase instance before committing to a conversion plan. Emits a per-dashboard complexity readout (visualization-type mix, MBQL aggregation patterns, native SQL flags, model-vs-question ratio, segment / metric references), usage signal from Metabase's activity API, and a value/cost-ranked migration shortlist that |
| Conversion | The subject of this QuickStart. Converts a single Metabase dashboard (or a batch via shortlist) to a Sigma data model and matching workbook with verified row-level parity. |
Here's how the two skills connect in a full migration — metabase-assessment hands the converter a ranked shortlist, and metabase-to-sigma produces the Sigma workbooks with a verified parity report:

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 second row — the demo dashboard reads from Metabase's bundled H2 Sample Database, which Sigma can't connect to, so we land a matching copy of the data in Snowflake first and let metabase-to-sigma bridge across.
Your situation | Skill(s) to use |
1 dashboard, model reads from your warehouse |
|
1 dashboard, model reads from a warehouse Sigma can't connect to (or from the H2 Sample Database) | Land the data in your warehouse first, then |
10+ dashboards (any data source) |
|
Auditing Metabase sprawl without converting yet |
|

First we need to clone the skill's GitHub repository, configure Metabase REST credentials, and capture your Sigma credentials.
The two skills live in sigmacomputing/quickstarts-public under metabase-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
mkdir -p ~/quickstarts-public
Step 2: Move into the new folder
cd ~/quickstarts-public
Step 3: Clone the repo without pulling any files yet
git clone --filter=blob:none --sparse https://github.com/sigmacomputing/quickstarts-public.git .
Step 4: Fill in only the metabase-migration-skills folder
git sparse-checkout set metabase-migration-skills
Step 5: Symlink metabase-to-sigma into the Claude skills folder
ln -s ~/quickstarts-public/metabase-migration-skills/metabase-to-sigma ~/.claude/skills/metabase-to-sigma
Step 6: Symlink metabase-assessment
ln -s ~/quickstarts-public/metabase-migration-skills/metabase-assessment ~/.claude/skills/metabase-assessment
Steps 5 and 6 should return with no error.

Step 7: 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 + the neutral ~/.sigma-migration/env file that the skill family uses to mint Sigma API tokens at runtime.
Run once per machine.
ruby ~/.claude/skills/metabase-to-sigma/scripts/setup.rb
The final prompt asks for a Connection ID (full warehouse-connection UUID, optional — Enter to skip). You can press Enter to skip — the kickoff prompt later in this QuickStart supplies the Snowflake connection ID inline. Capturing it here is useful only if you plan to run multiple migrations and want it persisted in ~/.sigma-migration/env.

Step 8: Capture your Metabase REST credentials.
The skill calls Metabase via its REST API. Auth supports two paths:
Admin settings > Authentication > API keys > Create API key. Set the group to Administrators for full read access. Copy the value (starts with mb_...).401.The skill reads Metabase credentials from the same ~/.sigma-migration/env file setup.rb populated for Sigma. Append your Metabase creds to it.
For the API key path:
cat >> ~/.sigma-migration/env <<'EOF'
export MB_BASE='https://{your-metabase-host}'
export MB_KEY='{your-api-key}'
EOF
For the username + password path:
cat >> ~/.sigma-migration/env <<'EOF'
export MB_BASE='https://{your-metabase-host}'
export MB_USER='{you@example.com}'
export MB_PASS='{your-password}'
EOF
MB_BASE is the Metabase server's base URL with no trailing slash and no /api suffix. For a local Docker container the value is usually http://localhost:3000. For a hosted instance it looks like https://{your-tenant}.metabaseapp.com.
Verify auth works by sourcing the env and running the session-helper script — it emits a shell function mb_get you can use to probe the API. The one-liner below lists every database connection Metabase has configured (the same set the skill discovers in Phase 0):
source ~/.sigma-migration/env && eval "$(bash ~/.claude/skills/metabase-to-sigma/scripts/get-metabase-session.sh)" && mb_get /api/database | python3 -c 'import sys,json; [print(d["id"], "-", d["name"], "-", d["engine"]) for d in json.load(sys.stdin).get("data",[])]'
You should see at least one line — 1 - Sample Database - h2 on a fresh Metabase install. If your Metabase has additional warehouse connections, they'll appear here too. The numeric id is the value the skill cross-references when it discovers your dashboard's source database in Phase 0.
If the command returns nothing or an error: double-check MB_BASE, MB_KEY (or MB_USER / MB_PASS), and that the API key's group has read access to the content you want to migrate.

Step 9: Verify Claude Code can invoke the skill.
Type claude in your terminal to start Claude Code, then invoke the skill:
claude
/metabase-to-sigma
Claude should start reading the reference files and ask what dashboard you want to convert.
Pause at that prompt — we'll hand it everything in one shot via the kickoff prompt in Run the Conversion:


The Metabase dashboard we're going to convert reads from Metabase's bundled H2 Sample Database, which Sigma can't connect to directly. The conversion still works — the skill bridges across sources — but Sigma needs the same data in a warehouse it CAN reach. We'll land a copy in Snowflake.
Data prep has two halves:
ORDERS and PRODUCTS tables from Metabase's Sample Database and hosted them as CSVs in Amazon S3. The COPY INTO statements below read from S3 directly — no local download needed.USE ROLE ACCOUNTADMIN;
USE WAREHOUSE COMPUTE_WH;
CREATE DATABASE IF NOT EXISTS QUICKSTARTS;
CREATE SCHEMA IF NOT EXISTS QUICKSTARTS.METABASE_ECOMMERCE;
USE SCHEMA QUICKSTARTS.METABASE_ECOMMERCE;
CREATE OR REPLACE FILE FORMAT metabase_csv_format
TYPE = CSV
FIELD_DELIMITER = ','
SKIP_HEADER = 1
FIELD_OPTIONALLY_ENCLOSED_BY = '"'
NULL_IF = ('', 'NULL')
EMPTY_FIELD_AS_NULL = TRUE
TIMESTAMP_FORMAT = 'MMMM DD, YYYY, HH12:MI AM';
CREATE OR REPLACE STAGE metabase_ecommerce_stage
URL = 's3://sigma-quickstarts-main/Metabase/'
FILE_FORMAT = metabase_csv_format;
CREATE OR REPLACE TABLE PRODUCTS (
ID NUMBER PRIMARY KEY,
EAN VARCHAR(13),
TITLE VARCHAR(200),
CATEGORY VARCHAR(50),
VENDOR VARCHAR(200),
PRICE NUMBER(10,2),
RATING NUMBER(3,1),
CREATED_AT TIMESTAMP_NTZ
);
CREATE OR REPLACE TABLE ORDERS (
ID NUMBER PRIMARY KEY,
USER_ID NUMBER,
PRODUCT_ID NUMBER,
SUBTOTAL NUMBER(12,2),
TAX NUMBER(12,2),
TOTAL NUMBER(12,2),
DISCOUNT NUMBER(12,2),
CREATED_AT TIMESTAMP_NTZ,
QUANTITY NUMBER
);
COPY INTO PRODUCTS FROM @metabase_ecommerce_stage/products.csv;
COPY INTO ORDERS FROM @metabase_ecommerce_stage/orders.csv;
SELECT 'PRODUCTS' AS TBL_NAME, COUNT(*) AS ROW_COUNT FROM PRODUCTS
UNION ALL
SELECT 'ORDERS', COUNT(*) FROM ORDERS;
SELECT
ROUND(SUM(TOTAL), 0) AS TOTAL_REVENUE,
COUNT(*) AS ORDER_COUNT
FROM ORDERS;
GRANT USAGE ON DATABASE QUICKSTARTS TO ROLE SIGMA_SERVICE_ROLE;
GRANT USAGE ON SCHEMA QUICKSTARTS.METABASE_ECOMMERCE TO ROLE SIGMA_SERVICE_ROLE;
GRANT SELECT ON ALL TABLES IN SCHEMA QUICKSTARTS.METABASE_ECOMMERCE TO ROLE SIGMA_SERVICE_ROLE;
GRANT SELECT ON FUTURE TABLES IN SCHEMA QUICKSTARTS.METABASE_ECOMMERCE TO ROLE SIGMA_SERVICE_ROLE;
Expected results:
ORDERS row count: 18,760TOTAL_REVENUE: ~ 1,510,618 — this is the baseline aggregate we'll cross-check against the Sigma element after the conversion.

The skill bridges across sources — Metabase can keep reading from its bundled H2 Sample Database (where ORDERS and PRODUCTS already live on any fresh Metabase install) while Sigma reads the matching data from the Snowflake schema you loaded in the previous section. Because the column names and types line up exactly (you extracted from H2 and loaded the same shape into Snowflake), the skill maps Metabase's MBQL field references onto Sigma's warehouse columns without you reconnecting Metabase at all.
Build a small four-card e-commerce dashboard against the Sample Database and save it. That dashboard is what you'll convert in the next phase.
Step 1: Build four questions against the Sample Database.
Click + New > Question. For each card below, pick Sample Database as the source. All four are pure MBQL — no native SQL — built entirely in Metabase's GUI query builder.
Card 1: Total Revenue (scalar)
OrdersSum of > TotalNumberTotal RevenueCard 2: Orders by Month (line)
OrdersCount of rowsCreated At > MonthLineOrders by MonthCard 3: Revenue by Category (bar)
OrdersProducts on Product IDSum of > TotalProducts > CategoryBarRevenue by CategoryCard 4: Top Products by Revenue (table)
OrdersProducts on Product IDSum of > TotalProducts > TitleSum of Total descending10TableTop Products by RevenueStep 2: Create the dashboard.
+ New > Dashboard. Name it Commerce Dashboard and add all four saved questions. Arrange them in any layout — the converter mirrors Metabase's grid coordinates onto Sigma's 24-column grid in the layout phase.
Step 3: Capture the dashboard ID.
With the dashboard open, look at the URL — /dashboard/{id}-{slug}. The integer is the dashboard ID. Save it; we'll paste it into the kickoff prompt in Run the Conversion.


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's easier to have it ready before you return to the Claude prompt that's still paused after the skill loads.
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:
Metabase 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.


The skill can run interactively, asking for the dashboard, 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 walks the pipeline directly, going straight from "go" through discover → convert → data model → workbook build → layout → parity.
If Claude is still running and paused at the skill's first prompt from Install and Configure the Skill, return to that terminal. If you closed Claude after that step, restart it now:
claude
/metabase-to-sigma
When Claude finishes loading the skill and asks What do you have ready:

...paste the block below. Substitute your own values where the placeholders are:
Dashboard ID — the Metabase dashboard's numeric ID, visible in the URL when you have the dashboard open. Metabase URLs look like https://{your-tenant}.metabaseapp.com/dashboard/{dashboard-id}-{slug} — the {dashboard-id} portion (the integer before any dash) is the value.SIGMA_CONNECTION_ID — your Snowflake connection ID (the one where you landed the sample data) from Sigma's Administration > ConnectionsSIGMA_FOLDER_ID — the folder ID you copied at the end of the previous sectionRun /metabase-to-sigma on the following. Walk every phase in SKILL.md end-to-end and stop only if a hard gate fails.
Metabase
- Credentials sourced from ~/.sigma-migration/env (MB_BASE, MB_KEY or MB_USER/MB_PASS)
- Dashboard ID: {your-dashboard-id}
Warehouse — different on each side
- Metabase reads from its bundled H2 Sample Database
- Sigma reads from Snowflake — database METABASE_ECOMMERCE
- Column names and types match exactly between H2 and Snowflake (same data extracted from H2 and loaded via CSV)
Sigma
- SIGMA_API_TOKEN = mint from ~/.sigma-migration/env
- SIGMA_CONNECTION_ID: {your-snowflake-connection-id}
- SIGMA_FOLDER_ID: {your-folder-id}
Options
- Name prefix: Metabase Demo
- Auto-approve mid-pipeline questions: yes
- Parity: data should match exactly since Snowflake is a direct copy of the H2 Sample Database. Report any deltas.
Don't declare GREEN until the parity gate passes and the visual-QA loop passes.
Claude reads the block, mints a fresh Sigma token from ~/.sigma-migration/env, sources the Metabase credentials, and walks the phases end-to-end. The rest of the run is hands-off until a gate or decision point.

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:
{{tag}}) in native queries become Sigma controls. Models with explicit aggregations become Sigma metrics; questions become workbook elements.type=error columns).sigma-mcp-v2 and compares against the Metabase card's aggregation. Each card reports PASS within tolerance or FAIL; the gate is GREEN only when all cards pass.Open the new workbook in Sigma to see the migrated dashboard:

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

Hand-polish items the skill flags rather than silently working around:
CumulativeSum, Offset) — degrade to placeholders with a warning manifest. Hand-author the Sigma equivalent on the affected element using RunningSum or window-function patterns.["segment", N]) — Metabase segments are saved filter snippets that don't have a direct Sigma analog. The skill surfaces them as flagged controls to hand-wire.ARRAY_AGG, Snowflake LISTAGG, Databricks collect_list — require the right warehouse dialect for the converter to rewrite. The skill auto-detects via the Sigma connection lookup; if dialect detection fails, pass --warehouse explicitly.
A single dashboard is the easy case. Real migrations involve Metabase instances with dozens to thousands of cards reading from a handful of shared models — and migrating them one-by-one through the converter loses the leverage of doing the planning work once. That's where the companion metabase-assessment skill comes in.
Point metabase-assessment at a Metabase instance and it inventories every dashboard, card, model, and database, scoring each on:
metabase-to-sigma actually applies, so the readout reflects what the tool will really do — not a generic guessmigrate-first, easy-win, moderate, needs-gap-scout, retire based on combined complexity + coverage + usage scoresThe output is a Sigma-branded readout.md you can share with stakeholders, plus a ranked migration shortlist sorted by value / (1 + cost) — the cheapest, highest-value dashboards to convert first.
The shortlist becomes input to a batch conversion plan — metabase-assessment groups dashboards that share the same model so one Sigma data model can serve a whole family of workbooks instead of producing N near-duplicate DMs. metabase-to-sigma consumes that plan in batch mode and runs the conversions concurrently.
Typical flow for a real migration engagement:
metabase-assessment against the target instance; review the shortlist with stakeholders.metabase-to-sigma and let it work through them.
The following is a "grab bag" of things that might come up during real conversions, with the fix for each.
python3 --version reports 3.9.x and the skill refuses to run:brew install python@3.12) or python.org, then use python3.12 -m pip install explicitly for any helpers. Avoid pip3 as a shorthand — it can quietly resolve back to the old interpreter.401 Unauthorized:Admin settings > Authentication > API keys), update MB_KEY (or MB_USER / MB_PASS) in ~/.sigma-migration/env, then re-source the env file and re-eval the get-metabase-session.sh helper so the new credentials are picked up in the current shell.metabase-discover.sh returns 404 Not Found for a dashboard you can see in the UI:CERTIFICATE_VERIFY_FAILED from a corporate proxy:curl works. Pull the proxy's root certificate out of Keychain and combine it with the macOS roots into a PEM Python can read, then point Python at it via SSL_CERT_FILE in ~/.sigma-migration/env. (Same recipe as the other migration QuickStarts in this family.)sigma-data-model-mcp). If it isn't installed locally, the skill stops at the gate. Pick option 6. Chat about this and tell Claude:Clone twells89/sigma-data-model-mcp into ~/Desktop/sigma-data-model-mcp for me, then run
npm install && npm run build in that directory. Once the build is done, come back to the gate and pick option 1.(Recommended) option.COPY INTO:Prepare the Demo Data includes the GRANT USAGE and GRANT SELECT statements — if you skipped or modified them, run them now with the role name your Sigma connection actually uses (find it in Sigma under Administration > Connections).ARRAY_AGG / LISTAGG / collect_list correctly. Dialect is auto-detected from the Sigma connection lookup but can fail silently. Re-run with --warehouse {bigquery|snowflake|databricks|redshift|postgres|athena} explicitly.Bash command — Contains shell syntax that cannot be statically analyzed — Do you want to proceed? prompts during the run:eval "$(...)" patterns to inject tokens dynamically. Claude Code's safety analyzer can't pattern-match these for blanket approval even in accept-edits mode. Click 1. Yes on each — it's expected behavior, not a misconfiguration. After the run, you can use the /fewer-permission-prompts skill to scan the transcript and add those patterns to your .claude/settings.local.json so subsequent runs are silent.
What you built is less a single conversion and more a repeatable migration path. The skill took a Metabase dashboard — cards, models, MBQL expressions, dashboard layout — and produced a Sigma data model, a workbook, and a row-level 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:
metabase-assessment scopes and prioritizes the instance; metabase-to-sigma converts and verifies. The same shape applies whether you're migrating one dashboard or every dashboard reading from a shared model.setup.rb has captured your Sigma credentials, the entire migration is one paste. The kickoff prompt reads the dashboard ID + warehouse coordinates + options in one shot, and the skill walks through every phase end-to-end without further interaction unless a gate genuinely needs your call.Prepare the Demo Data transfers to any warehouse Sigma can reach. For dashboards backed by Metabase's H2 Sample Database, land that data upstream first; the same pattern applies.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 Metabase instance.
Additional Resource Links
Blog
Community
Help Center
QuickStarts
Be sure to check out all the latest developments at Sigma's First Friday Feature page!
