metabase-representation-format
What is the Metabase Representation Format
Metabase represents user-created content as a tree of YAML files. Each file is one entity (a collection, card, dashboard, etc.). The format is portable across Metabase instances: numeric database IDs are replaced with human-readable names and entity IDs.
The full specification is in spec.md in this skill folder. Always Read it before creating or editing representation YAML files. The spec covers entity keys, folder structure, MBQL queries, native queries, visualization settings, click behaviors, parameters, and all entity types with examples.
Entities
The format defines 11 entity types. Each entity has a YAML JSON Schema in the schemas/ folder.
| Entity | SerDes Model | Schema File | Description |
|---|---|---|---|
| Collection | Collection |
schemas/collection.yaml |
Folder-like container for organizing content. Hierarchy via parent_id. Namespaces: null (main), "snippets", "transforms". |
| Card | Card |
schemas/card.yaml |
Question, model, or metric. Holds an MBQL or native dataset_query. Display types: table, bar, line, pie, scalar, etc. Card types: "question", "model", "metric". |
| Dashboard | Dashboard |
schemas/dashboard.yaml |
Grid layout (24 columns) of cards with filter parameters and optional tabs. Contains dashcards array for card placement and parameters array for filter controls. |
| Document | Document |
schemas/document.yaml |
Rich text page using ProseMirror AST. Can embed cards via cardEmbed nodes and link to entities via smartLink nodes. |
| Segment | Segment |
schemas/segment.yaml |
Saved filter definition scoped to a table. Definition is a pMBQL query with a single stage containing only source-table and filters. |
| Measure | Measure |
schemas/measure.yaml |
Saved aggregation definition scoped to a table. Definition is a pMBQL query with a single stage containing only source-table and exactly one aggregation. |
| Snippet | NativeQuerySnippet |
schemas/snippet.yaml |
Reusable SQL fragment referenced in native queries via {{snippet: Name}}. |
| Transform | Transform |
schemas/transform.yaml |
Materializes query or Python script results into a database table. Source is either MBQL/native query or Python script. |
| TransformTag | TransformTag |
schemas/transform_tag.yaml |
Label for categorizing transforms. Built-in types: "hourly", "daily", "weekly", "monthly", or null for custom. |
| TransformJob | TransformJob |
schemas/transform_job.yaml |
Scheduled job (cron) that executes transforms matching specific tags. |
| PythonLibrary | PythonLibrary |
schemas/python_library.yaml |
Shared Python source file available to Python-based transforms. |
Common schemas referenced by entity schemas live in schemas/common/:
id.yaml— entity_id (NanoID), user_id (email), database_id (name), table_id, field_idquery.yaml— MBQL and native query structure with expression validationref.yaml— field, expression, aggregation, metric, measure, segment referencesparameter.yaml— parameter definitions and targetstemporal_bucketing.yaml— datetime bucketing and extraction units
Entity Identification
Every entity has:
entity_id— 21-character NanoID (alphabet:A-Za-z0-9_-). Stable across renames/moves. Unique per entity type.serdes/meta— Array encoding the identity path. Each entry hasid,model, and optionallylabel(slugified name). The last entry'smodelfield determines the entity type.
Generate a NanoID:
head -c 21 /dev/urandom | base64 | tr -dc 'A-Za-z0-9_-' | head -c 21
Foreign key references use human-readable names instead of numeric IDs:
- Database FK: database name string (e.g.,
"Sample Database") - Table FK:
[database, schema, table]array (e.g.,["Sample Database", "PUBLIC", "ORDERS"]) - Field FK:
[database, schema, table, field, ...]array (4+ elements for JSON paths) - Collection/Card/Dashboard FK: entity_id (NanoID)
- User FK: email address
Folder Structure
Metabase imports entities from these directories only:
collections/**/*.yaml— cards, dashboards, documents, snippets, collectionsdatabases/**/segments/**/*.yaml— segment definitionsdatabases/**/measures/**/*.yaml— measure definitionspython_libraries/**/*.yaml(alsopython-libraries/) — Python library filestransforms/**/*.yaml— transform jobs and tags
Important: directory structure is for readability only. The authoritative source for collection membership is each entity's collection_id field. Collections are organized by namespace: main/ (regular content), snippets/ (SQL snippets), transforms/ (transform entities).
Queries
Queries use serialized pMBQL format. The outer wrapper is always:
"lib/type": mbql/query
database: Sample Database
stages:
- "lib/type": mbql.stage/mbql # or mbql.stage/native
...
MBQL stages (mbql.stage/mbql):
source-table: Table FK array (for physical tables)source-card: Card entity_id string (for saved questions/models)fields,joins,expressions,filters,breakout,aggregation,order-by,limit- Multi-stage queries use a flat
stagesarray — no nestedsource-query
Expression clauses always have options as the second element ([operator, {options}, ...args]):
- Field references:
[field, {options}, Field-FK-or-name]— options is always an object (empty{}when no options), never null - Expression references:
[expression, {}, "Name"] - Aggregation references:
[aggregation, {}, "uuid"]— UUID matcheslib/uuidon the referenced aggregation clause - All operators:
[count, {}],[sum, {}, field],[=, {}, a, b],[and, {}, clause1, clause2], etc. expressionsis an array; each top-level clause has"lib/expression-name"in its optionsfiltersis an array of filter clauses (implicitly ANDed)- Aggregations referenced by
order-bymust have"lib/uuid"in their options
Joins have their own stages array and conditions (plural) array.
Parameter mapping targets use legacy format: [field, Field-FK, null-or-options], [expression, name].
Native stages (mbql.stage/native):
native: SQL string with{{template_tag}}placeholderstemplate-tags: map defining each tag's type, display name, and default- Template tag types:
text,number,date,boolean,dimension,temporal-unit,card,snippet,table
See spec.md sections "MBQL Query" and "Native Query" for full syntax.
Schema Validation
Use @metabase/representations as a CLI tool to validate YAML files against the schemas:
npx @metabase/representations validate-schema --folder ./my-export
Omit --folder to validate the current directory. The tool:
- Finds YAML files in the recognized import directories
- Reads
serdes/metato determine the entity model - Validates against the corresponding JSON Schema
- Reports OK/FAIL per file with error details
- Exits with code 1 if any failures
Key Rules
- Every entity YAML file must have a
serdes/metaarray with the correctmodelvalue entity_idmust be a valid 21-character NanoIDcollection_iddetermines collection membership (not the file path)- Cards with
dashboard_idordocument_idare nested under that container - A card should never have both
dashboard_idanddocument_idset - Segment definitions: single stage with only
source-table+filters(no aggregation, joins, expressions) - Measure definitions: single stage with only
source-table+ exactly oneaggregation(no filters, joins, expressions) - Dashboard grid: 24 columns,
col + size_x <= 24, cards cannot overlap - Snippet
serdes/metauses modelNativeQuerySnippet(notSnippet)