The universal metrics layer for consistent metrics across your data stack. Compatible with 15+ semantic model formats.
- Supported Formats: Sidemantic (YAML, Python or SQL), Power BI TMDL, Cube, dbt MetricFlow, LookML, Hex, Rill, Superset, Omni, BSL, GoodData LDM, Snowflake Cortex, Malloy, OSI, AtScale SML, ThoughtSpot TML
- Databases: DuckDB, MotherDuck, PostgreSQL, BigQuery, Snowflake, ClickHouse, Databricks, Spark SQL (also via ADBC)
Documentation | GitHub | Docker Hub | Discord | Demo (50+ MB data download, runs in your browser with Pyodide + DuckDB)
Sidemantic ships Claude Code and Codex plugin metadata for two skills (modeler and webapp-builder). See Agent Plugin below to install.
Quickstart
Install:
Malloy support (uv):
uv add "sidemantic[malloy]"DAX and Power BI TMDL support (uv):
HTTP API server (uv):
Notebook widget (uv):
uv add "sidemantic[widget]" jupyterlab
uv run jupyter labMarimo (uv):
uv add "sidemantic[widget]" marimo
uv run marimo editimport duckdb from sidemantic.widget import MetricsExplorer conn = duckdb.connect(":memory:") conn.execute("create table t as select 1 as value, 'a' as category, date '2024-01-01' as d") MetricsExplorer(conn.table("t"), time_dimension="d")
Define models in SQL, YAML, or Python:
SQL (orders.sql)
MODEL (name orders, table orders, primary_key order_id);
DIMENSION (name status, type categorical);
DIMENSION (name order_date, type time, granularity day);
METRIC (name revenue, agg sum, sql amount);
METRIC (name order_count, agg count);YAML (orders.yml)
models: - name: orders table: orders primary_key: order_id dimensions: - name: status type: categorical - name: order_date type: time granularity: day metrics: - name: revenue agg: sum sql: amount - name: order_count agg: count
Python (programmatic)
from sidemantic import Model, Dimension, Metric orders = Model( name="orders", table="orders", primary_key="order_id", dimensions=[ Dimension(name="status", type="categorical"), Dimension(name="order_date", type="time", granularity="day"), ], metrics=[ Metric(name="revenue", agg="sum", sql="amount"), Metric(name="order_count", agg="count"), ] )
Query via CLI:
sidemantic query "SELECT revenue, status FROM orders" --db data.duckdbOr Python API:
from sidemantic import SemanticLayer, load_from_directory layer = SemanticLayer(connection="duckdb:///data.duckdb") load_from_directory(layer, "models/") result = layer.sql("SELECT revenue, status FROM orders")
DAX And TMDL
DAX/TMDL support lives behind the dax extra because it includes a native Rust parser:
Native Sidemantic YAML can preserve DAX expression source text for Power BI interoperability:
models: - name: sales table: sales primary_key: id dimensions: - name: doubled_amount type: numeric dax: "'sales'[amount] * 2" metrics: - name: revenue dax: "SUM('sales'[amount])"
Power BI TMDL projects can be loaded from a project root or definition/ folder. Embedded DAX measures, calculated columns, calculated tables, relationships, and TMDL passthrough metadata are parsed and preserved in model metadata:
from sidemantic import SemanticLayer, load_from_directory layer = SemanticLayer(connection="duckdb:///warehouse.duckdb") load_from_directory(layer, "powerbi_project/") print(layer.describe_models(["Sales"]))
TMDL can also round-trip back to disk:
from sidemantic.adapters.tmdl import TMDLAdapter TMDLAdapter().export(layer.graph, "exported_tmdl/")
CLI
# Query sidemantic query "SELECT revenue FROM orders" --db data.duckdb # Interactive workbench (TUI with SQL editor + charts) uvx --from "sidemantic[workbench]" sidemantic workbench models/ --db data.duckdb # PostgreSQL server (connect Tableau, DBeaver, etc.) uvx --from "sidemantic[serve]" sidemantic serve models/ --port 5433 # HTTP API server (JSON or Arrow) uvx --from "sidemantic[api]" sidemantic api-serve models/ --port 4400 --auth-token secret # Validate definitions sidemantic validate models/ # Model info sidemantic info models/ # Pre-aggregation recommendations sidemantic preagg recommend --db data.duckdb # Migrate SQL queries to semantic layer sidemantic migrator --queries legacy/ --generate-models output/
Demos
Workbench (TUI with SQL editor + charts):
uvx --from "sidemantic[workbench]" sidemantic workbench --demoPostgreSQL server (connect Tableau, DBeaver, etc.):
uvx --from "sidemantic[serve]" sidemantic serve --demo --port 5433HTTP API server (JSON or Arrow):
uvx --from "sidemantic[api]" sidemantic api-serve --demo --port 4400 --auth-token secretColab notebooks:
SQL syntax:
uv run https://raw.githubusercontent.com/sidequery/sidemantic/main/examples/sql/sql_syntax_example.py
Comprehensive demo:
uv run https://raw.githubusercontent.com/sidequery/sidemantic/main/examples/advanced/comprehensive_demo.py
Symmetric aggregates:
uv run https://raw.githubusercontent.com/sidequery/sidemantic/main/examples/features/symmetric_aggregates_example.py
Superset with DuckDB:
git clone https://github.com/sidequery/sidemantic.git && cd sidemantic uv run examples/superset_demo/run_demo.py
Cube Playground:
git clone https://github.com/sidequery/sidemantic.git && cd sidemantic uv run examples/cube_demo/run_demo.py
Rill Developer:
git clone https://github.com/sidequery/sidemantic.git && cd sidemantic uv run examples/rill_demo/run_demo.py
OSI (complex adtech semantic model):
git clone https://github.com/sidequery/sidemantic.git && cd sidemantic uv run examples/osi_demo/run_demo.py
OSI widget notebook (percent-cell Python notebook):
git clone https://github.com/sidequery/sidemantic.git && cd sidemantic uv run examples/osi_demo/osi_widget_notebook.py
See examples/ for more.
Core Features
- SQL query interface with automatic rewriting
- Automatic joins across models
- Multi-format adapters (Cube, MetricFlow, LookML, Hex, Rill, Superset, Omni, BSL, GoodData LDM, OSI, AtScale SML, ThoughtSpot TML, Graphene GSQL)
- SQLGlot-based SQL generation and transpilation
- Pydantic validation and type safety
- Pre-aggregations with explicit routing
- Predicate pushdown for faster queries
- Segments and metric-level filters
- Jinja2 templating for dynamic SQL
- PostgreSQL wire protocol server for BI tools
- HTTP API with JSON and Arrow IPC responses
Multi-Format Support
Auto-detects: Sidemantic (SQL/YAML), Power BI TMDL, Cube, MetricFlow (dbt), LookML, Hex, Rill, Superset, Omni, BSL, GoodData LDM, OSI, AtScale SML, ThoughtSpot TML, Graphene GSQL
sidemantic query "SELECT revenue FROM orders" --models ./my_modelsfrom sidemantic import SemanticLayer, load_from_directory layer = SemanticLayer(connection="duckdb:///data.duckdb") load_from_directory(layer, "my_models/") # Auto-detects formats
Databases
| Database | Status | Installation |
|---|---|---|
| DuckDB | ✅ | built-in |
| MotherDuck | ✅ | built-in |
| PostgreSQL | ✅ | uv add sidemantic[postgres] |
| BigQuery | ✅ | uv add sidemantic[bigquery] |
| Snowflake | ✅ | uv add sidemantic[snowflake] |
| ClickHouse | ✅ | uv add sidemantic[clickhouse] |
| Databricks | ✅ | uv add sidemantic[databricks] |
| Spark SQL | ✅ | uv add sidemantic[spark] |
Docker
The published image is sidequery/sidemantic on Docker Hub. Mount your models directory as a volume at /app/models:
docker run -p 5433:5433 -v ./models:/app/models sidequery/sidemantic
Demo mode (built-in sample data, no volume needed):
docker run -p 5433:5433 sidequery/sidemantic --demo
See examples/docker/ for MCP mode, env vars, building from source, and integration test services.
For Cloudflare Worker + Container deployment, see examples/cloudflare_containers/.
HTTP API
Start the API server:
uvx --from "sidemantic[api]" sidemantic api-serve models/ --db data.duckdb --port 4400 --auth-token secretCompile a structured semantic query:
curl -s http://localhost:4400/compile \ -H "Authorization: Bearer secret" \ -H "Content-Type: application/json" \ -d '{"dimensions":["orders.status"],"metrics":["orders.total_amount"]}'
Run a structured query as JSON:
curl -s http://localhost:4400/query \ -H "Authorization: Bearer secret" \ -H "Content-Type: application/json" \ -d '{"dimensions":["orders.status"],"metrics":["orders.total_amount","orders.order_count"]}'
Run a structured query as Arrow IPC:
curl -s http://localhost:4400/query \ -H "Authorization: Bearer secret" \ -H "Accept: application/vnd.apache.arrow.stream" \ -H "Content-Type: application/json" \ -d '{"metrics":["orders.order_count"]}' \ > result.arrow
Execute rewritten SQL over HTTP:
curl -s http://localhost:4400/sql \ -H "Authorization: Bearer secret" \ -H "Content-Type: application/json" \ -d '{"query":"SELECT status, total_amount FROM orders ORDER BY status"}'
Agent Plugin
Sidemantic ships a plugin bundle with Claude Code and Codex metadata for two skills:
modeler— build, validate, and query semantic modelswebapp-builder— generate analytics webapps from your models
Install in Claude Code:
claude plugin marketplace add sidequery/sidemantic && claude plugin install sidemantic@sidequeryInstall in Codex:
codex plugin marketplace add sidequery/sidemantic && codex plugin add sidemantic@sidequeryUse a local clone while developing:
claude --plugin-dir ./plugins/sidemantic codex plugin marketplace add . && codex plugin add sidemantic@sidequery
The Claude Code plugin manifest lives at plugins/sidemantic/.claude-plugin/plugin.json, and its marketplace lives at .claude-plugin/marketplace.json.
The Codex plugin manifest lives at plugins/sidemantic/.codex-plugin/plugin.json, and its repo-local marketplace lives at .agents/plugins/marketplace.json.
The skills also work with other SKILL.md-compatible agents by pointing them at plugins/sidemantic/skills/.
How mature is Sidemantic?
Sidemantic is an ambitious but young semantic layer project. You could encounter rough patches, especially with the more exotic features like converting between semantic model formats or serving semantic layers via the included Postgres protocol server.
Testing
This prints line coverage for sidemantic with missing lines in the terminal.
