Open source · AGPL v3

Your dashboards, as code

Write a YAML file. Run dac serve. Get a live dashboard in your browser, querying your warehouse directly.

YAML One command Real UI in your browser
localhost:8321/d/board-meeting
Board Meeting dashboard rendered by dac. ARR, customers, NRR, cash, runway, segment breakdowns, and top customers.

↑ Rendered live from dashboards/board-meeting.yml. 220 lines, 17 widgets, 3 named queries, querying DuckDB.

Trusted by forward-thinking teams

Internet Society
Paxie Games
Karaca
GrowDash
Obilet
Workhy
Buluttan
Lessmore
Spektra
Fomo Games
Rotatelab
Talemonster
Internet Society
Paxie Games
Karaca
GrowDash
Obilet
Workhy
Buluttan
Lessmore
Spektra
Fomo Games
Rotatelab
Talemonster
Internet Society
Paxie Games
Karaca
GrowDash
Obilet
Workhy
Buluttan
Lessmore
Spektra
Fomo Games
Rotatelab
Talemonster
kitUP
Fabrikatör
Joinco
Chimnie
ProphetX
Circle
Hyperlab
Moonstep
Agave Games
Kyoso
Digital Moka
Surpass Games
kitUP
Fabrikatör
Joinco
Chimnie
ProphetX
Circle
Hyperlab
Moonstep
Agave Games
Kyoso
Digital Moka
Surpass Games
kitUP
Fabrikatör
Joinco
Chimnie
ProphetX
Circle
Hyperlab
Moonstep
Agave Games
Kyoso
Digital Moka
Surpass Games

How it works

Connection. YAML. Server.

One file points at your warehouse, another defines the dashboard, then dac serve.

1

Point at a connection

Name your warehouses in .bruin.yml. DuckDB, Postgres, BigQuery, Snowflake. Anything Bruin connects to.

environments:
  default:
    connections:
      postgres:
        - name: warehouse
          host: db.internal
          database: analytics
2

Write a dashboard file

Drop a .yml or .dashboard.tsx into dashboards/. Filters, widgets, SQL, all in one file.

name: Revenue
connection: warehouse
rows:
  - widgets:
      - type: metric
        sql: SELECT SUM(amount) ...
        column: value
3

One command to serve

dac serve turns the directory into a live UI. Embed it, ship it, or run it in CI.

$ dac serve --dir ./dashboards
listening on http://localhost:8321
✓ Revenue   1 row, 540ms
✓ Trend     24 rows, 510ms

From file to dashboard

Write a file. Get a dashboard.

No project setup. No auth flows. The YAML below is the whole dashboard.

revenue.ymlYAML
name: Revenue
connection: warehouse

filters:
  - name: date_range
    type: date-range
    default: last_30_days

rows:
  - widgets:
      - name: Revenue (30d)
        type: metric
        col: 4
        prefix: "$"
        format: number
        column: value
        sql: |
          SELECT SUM(amount) AS value
          FROM sales
          WHERE created_at BETWEEN
            '{{ filters.date_range.start }}'
            AND '{{ filters.date_range.end }}'

      - name: Revenue Trend
        type: chart
        chart: area
        col: 8
        x: month
        y: [revenue]
        sql: |
          SELECT date_trunc('month', created_at) AS month,
                 SUM(amount) AS revenue
          FROM sales GROUP BY 1
preview what you'd see
Revenue (30d)
$1,284,320
▲ 12.3% vs prior
Revenue Trend

Filters live in the URL. SQL templated with Jinja. Result cached per refresh.interval.

Need loops, components, or data-driven layouts? Same widgets, JSX syntax:

explorer.dashboard.tsxTSX
// Discover regions at load time, generate one KPI per region.
const regions = query("warehouse", "SELECT DISTINCT region FROM sales")

export default (
  <Dashboard name="Sales Explorer" connection="warehouse">
    <Filter name="date_range" type="date-range" default="last_30_days" />
    <Row>
      {regions.rows.map(([r]) =>
        <Metric name={r} prefix="$" col={12 / regions.rows.length}
          column="value" format="number"
          sql={`SELECT SUM(amount) FROM sales WHERE region = '${r}'`} />
      )}
    </Row>
  </Dashboard>
)

Use with Claude

Build dashboards by describing them.

Hand the pack to Claude, Cursor, or Codex. Say "build a churn dashboard from our Stripe events". Get YAML back, validated against your real database.

dac × Claude pack

19 KB · zip

Unzip into your project root. Claude Code picks up the skill automatically.

📄  CLAUDE.mdproject memory
📁  .claude/skills/create-dashboard/auto-loaded skill
📄  └─ SKILL.md38 KB · full schema
📁  dashboards/3 working examples

Extract into your repo

unzip dac-claude-pack.zip -d ./my-project

Claude Code auto-loads CLAUDE.md and .claude/skills/ from the project root.

Why dac

Dashboards belong next to your SQL.

One file. One git repo. One review process.

{}

YAML or TSX

YAML for static layouts. TSX when you need loops, components, or dashboards that adapt to schema at load time.

SQL

Real queries, no middleware

Queries hit your warehouse directly. Filters compile to Jinja-templated SQL. Results cache per widget at the TTL you set.

Σ

Optional semantic layer

Define metrics:, dimensions:, and a source: table once. Scalar metrics merge into a single SQL query, charts auto-generate GROUP BYs.

Embed anywhere

Ship the Go binary inside your app. Mount as a route, drop into an iframe, or compile the dashboard package directly into your codebase. No SaaS dependency, no proxy, no API calls leaving your network.

vs the alternatives

Honest tradeoffs.

dac is a fit if you already version SQL and review changes in PRs. If your dashboards are authored by non-technical users in a clicky UI, you want a BI tool, not this.

dacLooker / MetabaseHex / ModeEvidence / Observable
Definition formatYAML or TSX in your repoClick-driven UI, LookMLSQL + Python notebookMarkdown + SQL or JS
Code reviewgit diff, PR commentsUI history onlySnapshot diffsgit diff, PR comments
Live queriesYes, cached per widgetYesYesStatic export, rebuild to refresh
Connection layerBruin, 30+ DBs, shared with rest of stackBuilt-in (BI-shaped)Built-inPer-tool, DIY
Cost at 50 users$0, your infra$$$ per seat$$ per seat$0
AI-native authoringFirst-class, see belowLimited betaLimited betaLimited

Connections

Bring your own warehouse.

Anything bruin query can hit, dac can render.

DuckDB
Postgres
BigQuery
Snowflake
ClickHouse
MotherDuck
Redshift
Databricks
MS SQL Server
Athena
Trino
MySQL
Oracle
MongoDB Atlas
Elasticsearch
S3
Microsoft Fabric
Synapse
Dataproc Serverless
EMR Serverless

Command line

One command to ship.

dac serve on day one. The rest are for CI.

dac serve --dir .Start a live dev server with file watching. Default port 8321.
dac validateStatic checks. YAML syntax, column sums, query refs.
dac checkDeep check. Actually executes every query against the real connection. CI-friendly.
dac query --widget "Revenue"Run a single widget's query inline. Output as table, JSON, or CSV.
dac lsList all discovered dashboards with widget counts and connection.

Get started

Your first dashboard, live today

One curl. One YAML file. One dac serve.

curl -fsSL https://raw.githubusercontent.com/bruin-data/dac/main/install.sh | bash