skills/metabase-modular-embedding-to-modular-embedding-sdk-upgrade/SKILL.md
Migrates a React project from Metabase Modular embedding (embed.js web components) to the Modular embedding SDK (@metabase/embedding-sdk-react). Use when the user wants to switch from embed.js web components to React SDK components (MetabaseProvider). This is not a version upgrade — it changes the embedding technology.
npx skillsauth add metabase/agent-skills metabase-modular-embedding-to-modular-embedding-sdk-upgradeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Follow the workflow steps in order — do not skip any step. Create the checklist first, then execute each step and explicitly mark it done with evidence. Each step's output feeds into the next, so skipping steps produces wrong migrations.
If you cannot complete a step due to missing info or tool failure, you must:
Your response should contain these sections in this order:
Each step section should end with a status line:
Status: ✅ complete or Status: ❌ blockedThis migration touches code that may contain API keys, JWTs, or auth configuration values (e.g., window.metabaseConfig). Rules:
config.js:12"), never echo the value itselfThe workflow is designed as a pipeline:
Round 1 (grep+glob+pkg) ──► Round 2 (prepare.sh) ──► Round 3 (read-sources.sh) ──► Step 3 (mapping, inline)
│
Step 4 per-file:
├── Convert FileA
├── Convert FileB
└── Convert FileC
│
Step 5 (typecheck) ──► Step 6
In Claude Code, use parallel tool calls or run_in_background: true for sub-agents.
Do not parse repo branches, commits, PRs, or issues — they're noisy and irrelevant.
Steps 1+2 must complete in 3 tool-call rounds.
Round 1 — discovery (all concurrent, single message):
metabase-dashboard, metabase-question, metabase-browser in *.{jsx,tsx,js,ts} fileswindow.metabaseConfig/app/embed.js (to find the script tag)package.json (to confirm React dependency and detect package manager)yarn.lock, pnpm-lock.yaml, package-lock.json)npm view @metabase/embedding-sdk-react version (if target not specified by user)All tool calls in one message.
Round 2 — prepare.sh + fetch docs (concurrent):
bash <skill-path>/scripts/prepare.sh {TARGET_VERSION}
Downloads the target SDK npm package and extracts it. Outputs SDK_TMPDIR and d.ts availability.
In the same message, fetch llms-embedding-full.txt for the target version (see "Allowed documentation sources" for URL format).
Round 3 — read-sources.sh (single Bash call):
bash <skill-path>/scripts/read-sources.sh {SDK_TMPDIR}
Dumps the target SDK's d.ts type definitions to stdout.
After Round 3, output Step 1 Results + Step 2 Results + Step 3 Migration Mapping with zero additional tool calls. Produce Step 3 inline right after the data is loaded.
This skill converts Modular embedding (web-components-based) used inside a React app to the Modular embedding SDK (@metabase/embedding-sdk-react). The project must already be a React application with Modular embedding web components in JSX/TSX files.
If the project is not React-based, this skill does not apply. If the project uses iframes instead of web components, use the metabase-full-app-to-modular-embedding-upgrade skill instead.
<metabase-dashboard>, <metabase-question>, <metabase-browser> web components in JSX/TSX with their SDK React equivalents@metabase/embedding-sdk-react npm package<MetabaseProvider> at the appropriate level in the React component treewindow.metabaseConfig to MetabaseProvider config propsembed.js <script> tag (typically in index.html or the HTML entry point)window.metabaseConfig assignmentFetch the version-specific llms-embedding-full.txt using this URL:
https://www.metabase.com/docs/v0.{VERSION}/llms-embedding-full.txt
The version in the URL uses the format v0.58 (normalize: strip leading v or 0., drop patch — e.g., 0.58.1 → 58 → URL uses v0.58). This single file contains all embedding documentation for that version, optimized for LLM consumption.
Other constraints:
Do all version detection in Round 1.
metabase/metabase:v, metabase/metabase-enterprise:v), METABASE_VERSION, or version references in env files. If undetected, AskUserQuestion.npm view @metabase/embedding-sdk-react version to find the latest matching version.yarn.lock → yarn, pnpm-lock.yaml → pnpm, package-lock.json → npm.Create a checklist to track progress. In Claude Code, use TaskCreate/TaskUpdate tools:
Verify before starting:
package.json for react in dependencies or devDependencies. If not present, mark ❌ blocked — this skill only applies to React projects.<metabase-* usage in .jsx, .tsx, .js, or .ts files (not only in plain HTML). If web components are only in plain HTML files, mark ❌ blocked — this skill requires web components to already be used inside React.Step 1 happens in Round 1 — grep only, no file reading.
Grep for these patterns (all in parallel):
<metabase-dashboard in *.{jsx,tsx,js,ts} files — dashboard web components<metabase-question in *.{jsx,tsx,js,ts} files — question web components<metabase-browser in *.{jsx,tsx,js,ts} files — collection browser web componentswindow.metabaseConfig — global config assignment (may be in index.html or a JS/TS file)/app/embed.js — the embed.js script tag (typically in index.html)This returns file paths + matching lines. Do not read project files yet — that happens in Step 4.
Output: a file list grouped by category:
Web components (JSX/TSX):
- src/pages/Dashboard.tsx:15 — <metabase-dashboard dashboard-id="123">
- src/pages/Analytics.tsx:22 — <metabase-question question-id="456">
Config:
- public/index.html:8 — window.metabaseConfig = { ... }
Script tag:
- public/index.html:12 — <script defer src="...embed.js"></script>
Run prepare.sh in Round 2 (see round budget). Then read-sources.sh in Round 3 to load the d.ts into context.
If d.ts is available, extract from it:
MetabaseProvider, dashboard/question/collection components)MetabaseProvider config type (what fields it accepts)The embedding docs (llms-embedding-full.txt) fetched in Round 2 provide supplementary reference for component usage, configuration options, and migration guidance. Use them alongside the d.ts for a complete picture.
If d.ts is not available (SDK versions before 0.52.0 do not ship a single index.d.ts), use the embedding docs as the primary API reference instead. If neither d.ts nor docs are available, mark Step 2 ❌ blocked.
Scope: only map components and config actually found in Step 1's scan.
Produce a mapping that covers:
For each web component found in Step 1, identify the SDK React equivalent from the d.ts. Map attributes to props:
## Migration Mapping
### <metabase-dashboard> → {SDK dashboard component from d.ts}
- `dashboard-id` → `dashboardId` (camelCase)
- `with-title` → `withTitle` (boolean prop)
- `drills` → check d.ts for equivalent prop name
- Other attributes → map to corresponding React props from d.ts
### <metabase-question> → {SDK question component from d.ts}
- `question-id` → `questionId` (camelCase)
- Other attributes → map from d.ts
### <metabase-browser> → {SDK collection component from d.ts}
- `initial-collection` → check d.ts for prop name
- Other attributes → map from d.ts
For each mapping, resolve the target prop type to its concrete type. If an attribute has no SDK equivalent, note it as "dropped (not supported in SDK)" or "requires alternative approach".
Map window.metabaseConfig fields to MetabaseProvider config:
### Auth & Config
- window.metabaseConfig.instanceUrl → config.metabaseInstanceUrl (check d.ts for exact field name)
- window.metabaseConfig.jwtProviderUri → authConfig.jwtProviderUri or authConfig.authProviderUri or config.authProviderUri (check d.ts — the field was renamed from `jwtProviderUri` to `authProviderUri` in some versions)
- window.metabaseConfig.locale → locale prop or config field (check d.ts)
The d.ts is the authoritative source for field names — do not guess. If a window.metabaseConfig field has no equivalent in the SDK config type, note it.
Determine where to add <MetabaseProvider>:
App.tsx, App.jsx, or equivalent)<script> tag: identify file and exact code to removewindow.metabaseConfig assignment: identify file and exact code to removeBefore per-file work:
{package-manager} add @metabase/embedding-sdk-react@{TARGET_VERSION}
<script> tagwindow.metabaseConfig assignment<MetabaseProvider> wrapper at the determined location with the migrated configPer-file task (for each file containing web components):
"false" → {false}, "123" → {123})Parallelization strategy:
When converting HTML attribute values to React props:
"true" / "false" → boolean {true} / {false}"123" → number {123}{dashboardId}) → keep as-isnpm run typecheck, tsc --noEmit, or the project's equivalent.node_modules/@metabase/embedding-sdk-react/dist/index.d.ts for each failing symbol.If the project does not use TypeScript, manually review each change against the d.ts to verify prop names and types match. Mark Step 5 ✅ with a note that validation was manual.
Organize into these sections:
1. Changes applied — list every file modified and a one-line description of each change.
2. Component mapping — table showing each old web component → new React component:
| File | Old | New | Props Changed |
|---|---|---|---|
| src/Dashboard.tsx | <metabase-dashboard dashboard-id="1"> | <InteractiveDashboard dashboardId={1} /> | dashboard-id → dashboardId |
3. Auth migration — how window.metabaseConfig was converted to MetabaseProvider config.
4. Removed artifacts — embed.js script tag, window.metabaseConfig, any dead code.
5. New capabilities — SDK features now available that weren't in Modular embedding (e.g., React hooks, typed callbacks, sub-components like InteractiveQuestion.FilterBar). Keep brief.
6. Instance requirements — minimum Metabase instance version needed. The Metabase instance version must match the SDK version (e.g., SDK 0.58.x requires Metabase v0.58+).
Doc fetching:
llms-embedding-full.txt returns 404, verify the Metabase version number and retry. If still failing, proceed without docs (d.ts is the primary source).npm pack:
npm pack fails for the target version, it likely doesn't exist on npm. Mark as ❌ blocked and inform the user.npm install:
--legacy-peer-deps (npm) or equivalent. Report the conflict to the user.tools
Drive a Metabase instance from the terminal via the `mb` CLI. Authenticate with named profiles; inspect databases (list, get, full metadata rollup, schemas, tables in a schema) and trigger manual schema sync / field-values rescan; inspect tables, fields; list/get/create/update/archive cards (questions, models, metrics) and run them as JSON/CSV/XLSX; list/get/create/update dashboards and patch dashcards; list/get/create collections and traverse the hierarchy by id, entity_id, or "root"/"trash" (with items and recursive tree); list/get/create/update/archive native query snippets, segments, and measures; author/update/run transforms and schedule transform-jobs; read/update settings; search content (cards, dashboards, collections, transforms, metrics); manage Enterprise workspaces; git-sync to/from a git remote (status, dirty, import, export, branches, stash, add/remove a collection from sync). Use whenever the user wants to interact with a Metabase from the terminal — "log into metabase", "what profiles do I have", "list cards", "run card 42 as CSV", "create a transform", "list dashboards", "move a dashcard", "list collections", "what's in collection 4", "show the collection tree", "list snippets", "create a segment", "archive a measure", "search metabase for X", "spin up a workspace", "import the latest changes", "add a directory to git sync", "set a setting", "what schemas are in this database", "trigger a sync", "rescan field values", or anything hitting `mb <verb>`.
development
Runs the Metabase semantic checker against a tree of Representation Format YAML files to verify that all references resolve — cross-entity references (collection_id, dashboard_id, parent_id, parameter source cards, snippet references, transform tags, etc.) and references to columns inside MBQL and native queries. Slow (≥1 min per run). Only use when the user explicitly asks to verify entity references or column references in MBQL/SQL queries; in most cases this runs as a CI step, not locally. Requires database metadata on disk (by default `.metadata/table_metadata.json`).
development
Understands the Metabase Database Metadata Format — a YAML-based on-disk representation of databases, tables, and fields synced from a Metabase instance. Use when the user needs to read, edit, or understand metadata files produced by `@metabase/database-metadata`, or when reasoning about a project's schema (columns, types, FK relationships) through the `.metadata/databases` folder.
development
Understands the Metabase Representation Format — a YAML-based serialization format for Metabase content (collections, cards, dashboards, documents, segments, measures, snippets, transforms). Use when the user needs to create, edit, understand, or validate Metabase representation YAML files, or when working with Metabase serialization/deserialization (serdes). Covers entity schemas, MBQL and native queries, visualization settings, parameters, and folder structure.