Linear × Metabase

How to build Linear analytics dashboards in Metabase

Linear is where your team plans and ships work. Metabase is where you turn that activity into shared, trustworthy dashboards. Because Metabase reads from SQL databases, the reliable way to connect them is a small pipeline: sync Linear into a database or warehouse on a schedule, then point Metabase at it. This guide walks through that path end to end — including a free option with no paid connector.

Heads up: Metabase connects to SQL databases and warehouses — it does not ship a native Linear connector. For dashboards that need history and reliability, you'll sync Linear into a database first (covered below).

How do you connect Linear to Metabase?

Metabase connects to SQL databases and warehouses — not to SaaS APIs directly, and there's no native Linear connector. So connecting Linear to Metabase means one thing: run a small pipeline that copies Linear data into a database on a schedule, then connect Metabase to that database. Once the data lands, the models, metrics, and SQL later in this guide all work.

The good news: this doesn't require a paid tool. Use a managed connector if you want zero maintenance, or a free, code-based sync you host yourself — both are covered in Build the pipeline below, and in more depth in our guide to building a data pipeline.

What can you analyze from Linear data in Metabase?

  • Throughput / velocity — issues and points completed per cycle
  • Cycle time and lead time — from start (or created) to done
  • Work-in-progress and flow — how much is open and where it sits
  • Project and initiative health — scope, progress, and slippage
  • Bug vs. feature mix — where engineering time actually goes
  • Estimation accuracy — estimated vs. actual effort over time
  • Team and individual load — open and completed work distribution
  • Backlog age and aging issues — what's getting stale

Which Linear dashboards should you build in Metabase?

For: Eng leads, EMs

Engineering velocity

Track how much the team ships each cycle and whether it's stable.

  • Completed issues per cycle (bar)
  • Completed estimate points per cycle (bar)
  • Rolling 4-cycle average throughput (line)
  • Carryover: started but not finished in-cycle (number + trend)
For: Eng leads, delivery

Cycle time & flow

Understand how long work takes and where it gets stuck.

  • Median cycle time by week (line)
  • Cycle time distribution / p50–p90 (histogram or table)
  • Current WIP by state (bar)
  • Aging WIP: open issues by days-in-progress bucket (table)
For: PMs, leadership

Project & initiative health

See whether projects are on track by scope and progress.

  • Project completion % vs. target date (table)
  • Scope change: issues added after project start (line)
  • Projects at risk: past target with open issues (table)
  • Initiative roll-up: progress across child projects (bar)
For: Eng, QA, support liaison

Quality & bug load

Watch bug inflow vs. resolution and where defects cluster.

  • Bugs created vs. resolved per week (dual line)
  • Open bug count by priority (bar)
  • Median time-to-resolution for bugs (line)
  • Bug share of total completed work (number)

How do you build the Linear → Metabase pipeline?

Every pipeline is the same four stages: extract from Linear's API, load into a database, model the raw tables into clean ones, and visualize in Metabase. You can assemble this with a managed connector or a free script you host yourself.

No paid tool required. A fully free stack: a small dlt or hand-written script (extract) → a free Postgres database like Neon or Supabase (load) → a scheduler such as GitHub Actions cron (host) → Metabase (visualize). For small volumes the whole thing can run at $0.

1. Extract and load (pick one)

  • dlt (free, code) — an open-source Python library that handles pagination, schema, and incremental loads against Linear's GraphQL API. The lightest path to a maintainable, no-vendor sync.
  • Linear GraphQL API (free, raw) — write your own script that paginates issues, cycles, and projects and upserts on a schedule. Most control, and an AI assistant can scaffold it in minutes.
  • Airbyte — has a Linear source connector. Free if you self-host the open-source version; paid on Airbyte Cloud. Good when you want a UI and many sources at once.
  • Fivetran (paid, managed) — does not offer a native Linear connector; use dlt, the API, or Airbyte instead.

2. Where to run it (hosting)

Writing the sync is the easy part now — the real question is where it runs on a schedule. From lowest to highest maintenance:

  • GitHub Actions (cron) — built-in scheduler, encrypted secrets, and free minutes that cover daily or hourly syncs. The simplest "run my script every day" option.
  • Serverless functions — Cloud Functions, AWS Lambda, or Modal on a timer. Generous free tiers; scales without a server to manage.
  • Managed cron platforms — Railway or Render cron jobs for a few dollars a month, with logs and retries built in.
  • An always-on VM + cron — full control, but you own uptime and patching.

3. Where to land it (destination)

  • Neon / Supabase / self-hosted Postgres — simplest and cheapest, free tiers available, and Metabase works great with it. Start here.
  • BigQuery / Snowflake / Redshift — reach for these once volumes grow or you're joining Linear with many other sources.

Notes

  • Land raw tables first, then build clean models on top — don't report off raw JSON.
  • Schedule syncs to match how fresh dashboards need to be (hourly is usually plenty).
  • Capture state-change history if you want accurate cycle/lead time; raw snapshots lose transitions.

Can you generate a Linear dashboard with AI?

Yes — and once Linear data is synced into a database, this is the fastest way to a strong first draft. First give an AI assistant a way to read your Metabase schema and create questions and dashboards, then paste the prompt below into Codex, Claude, Cursor, or any assistant wired up to Metabase. It builds the dashboard from your database tables and tells the agent to skip metrics the schema can't support instead of faking them.

Two ways to let an assistant query and build in Metabase

Both connect to a Metabase instance that's already pointed at your synced database — the pipeline above moves the data; these just let the assistant read and write Metabase. Pick whichever fits your setup:

Metabase MCP

Best for
Chat clients (Claude, Cursor, Codex)
Enable
Admin → AI → MCP
Endpoint
https://<your-metabase>/api/metabase-mcp
Auth
OAuth handled by Metabase

Metabase CLI

Best for
Terminal agents, scripts, and CI
Install
npm install -g @metabase/cli
Auth
Browser OAuth (v62+) or an API key
Docs
@metabase/cli

Set up the Metabase MCP server

Enable it under Admin → AI → MCP, then point your client at the endpoint:

ClaudeClaude Code CLI
# Metabase built-in MCP (replace with your instance URL)
claude mcp add --transport http metabase https://your-metabase.example.com/api/metabase-mcp
Cursor~/.cursor/mcp.json or .cursor/mcp.json
{
  "mcpServers": {
    "metabase": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://your-metabase.example.com/api/metabase-mcp"]
    }
  }
}

Clients with native remote support can use a "url" field instead of the mcp-remote bridge. Confirm the current endpoint in the Metabase MCP docs.

Set up the Metabase CLI

Install it globally, then authenticate once (the binary is mb):

Install & authenticateshell
# Install the CLI (the binary is `mb`)
npm install -g @metabase/cli

# Authenticate once — opens your browser on Metabase v62+, or use an API key
mb auth login --url https://your-metabase.example.com
mb auth status

On Metabase v62+ mb auth login opens your browser; older servers fall back to an API key. A terminal-based assistant can then inspect your schema (mb db schemas, mb table get --include fields) and create content (mb card create, mb dashboard create) against the synced tables.

Prompt: build the Linear Delivery Health dashboard

With MCP or the CLI connected, paste this into your assistant to generate the dashboard:

Prompt for creating a Linear Delivery Health dashboard
Create a polished Metabase dashboard for Linear analytics using the available
Linear tables in this database.

Goal: Help engineering and product leaders understand delivery health, cycle
progress, backlog risk, and bug/support load from Linear data.

First, inspect the schema and identify the available Linear tables. Do not assume
exact table names. Map the available raw tables into these analytical concepts
where possible: Issues, Teams, Projects, Cycles, Workflow states, Labels, Users,
and Issue history / status-change events if available.

Important:
- Build the dashboard only from durable database/warehouse tables.
- If status history is missing, do not calculate true cycle time, scope change,
  time in status, or reopen rate. Use a caveat instead.
- Do not claim Metabase connects natively to Linear unless that is explicitly
  true in this environment.

Dashboard title: Linear Delivery Health

Sections:
1. Executive summary (KPI cards): Open issues; Issues completed last 7 days;
   Issues created last 7 days; Median cycle time (only if a reliable
   started_at/status-history field exists); High-priority open bugs; Active
   projects at risk (only if project target/status fields exist).
2. Delivery throughput: Completed issues by week; Created vs completed by week;
   Completed issues by team; Completed issues by priority.
3. Cycle health: Current cycle planned vs completed; Incomplete issues by team
   and cycle; Carryover rate (only if cycle timing/snapshots exist); Scope added
   after cycle start (only if issue-cycle history/snapshots exist).
4. Project health: Active projects by status; Open issues by project and
   workflow state; Projects with target dates in next 30 days; Past-due/blocked
   projects (if fields exist).
5. Backlog and aging: Open backlog by team; Open issues by workflow state;
   Oldest open issues table; Unassigned/untriaged issues.
6. Bug and support load: New bugs by week; Resolved bugs by week; Open
   high-priority bugs by age; Bug/support issues by product area or label
   (use labels to identify bugs/support/customer requests if available).

Filters: Team, Project, Cycle, Label, Priority, Workflow state, Assignee,
Date range.

Before finalizing, create or recommend reusable Metabase models:
modeled_linear_issues, modeled_linear_teams, modeled_linear_projects,
modeled_linear_cycles, modeled_linear_workflow_states, modeled_linear_labels,
and modeled_linear_issue_events (only if history exists).

Output: Build the dashboard if you have permission; otherwise provide the exact
questions, SQL, model definitions, and layout. Include caveats for any metric
that cannot be calculated from the available schema. Keep it practical, dense,
and executive-readable. Avoid vanity metrics.

How should you model Linear data in Metabase?

Core tables

TableGrainKey columns
issuesone row per issueid, identifier, team_id, project_id, cycle_id, state_type, priority, estimate, assignee_id, created_at, started_at, completed_at, canceled_at
cyclesone row per cycleid, team_id, number, starts_at, ends_at
projectsone row per projectid, name, state, target_date, started_at, completed_at, lead_id
teamsone row per teamid, name, key
usersone row per memberid, name, email, active

Modeling advice

  • Add derived cycle_time = completed_at - started_at and lead_time = completed_at - created_at in your model layer, not in every question.
  • Normalize state into a small state_type set (backlog/started/completed/canceled) so charts stay stable when workflow states change.
  • If you need historical WIP/flow, model an issue_state_history table from API change events; point-in-time snapshots are unreliable.
  • Treat labels as a bridge table (issue_labels) so an issue can carry many labels without exploding rows.
  • Define "completed" once (state_type = 'completed') and reuse it everywhere to avoid metric drift.

Which Linear metrics should you track in Metabase?

MetricDefinitionNotes
Throughput (issues completed)Count of issues with state_type = 'completed' in a period.Simplest velocity signal; pair with points to avoid gaming by issue-splitting.
Velocity (points completed)Sum of estimate for issues completed in a cycle.Only meaningful if the team estimates consistently.
Cycle timecompleted_at − started_at, usually a median.Use median (p50) and p90; averages are skewed by outliers.
Lead timecompleted_at − created_at.Captures queue/backlog wait, not just active work.
Work in progress (WIP)Count of issues with state_type = 'started' right now.High WIP often correlates with longer cycle time.
Carryover rateShare of issues started in a cycle but completed later.Signals over-commitment or scope churn.
Bug ratioCompleted bug issues ÷ all completed issues.Watch the trend, not a single number.
Estimation accuracyRelationship between estimate and actual cycle time.Look for systematic under/over-estimation, not per-issue noise.

What SQL powers Linear dashboards in Metabase?

These assume the modeled tables above (PostgreSQL dialect). Adjust identifiers to match your warehouse.

Throughput per cyclePostgreSQL

Issues completed in each cycle, by team.

SELECT
  t.name        AS team,
  c.number      AS cycle,
  c.starts_at,
  COUNT(*)      AS issues_completed,
  SUM(i.estimate) AS points_completed
FROM issues i
JOIN cycles c ON c.id = i.cycle_id
JOIN teams  t ON t.id = i.team_id
WHERE i.state_type = 'completed'
GROUP BY t.name, c.number, c.starts_at
ORDER BY c.starts_at;
Median cycle time by weekPostgreSQL

Flow trend using the median of completed_at − started_at.

SELECT
  date_trunc('week', i.completed_at)            AS week,
  percentile_cont(0.5) WITHIN GROUP (
    ORDER BY EXTRACT(EPOCH FROM (i.completed_at - i.started_at)) / 86400.0
  )                                             AS median_cycle_days
FROM issues i
WHERE i.state_type = 'completed'
  AND i.started_at IS NOT NULL
GROUP BY 1
ORDER BY 1;
Current WIP by statePostgreSQL

Snapshot of open work right now.

SELECT
  i.state            AS state,
  COUNT(*)           AS open_issues
FROM issues i
WHERE i.state_type = 'started'
GROUP BY i.state
ORDER BY open_issues DESC;
Projects at riskPostgreSQL

Projects past their target date with open issues remaining.

SELECT
  p.name,
  p.target_date,
  COUNT(*) FILTER (WHERE i.state_type <> 'completed') AS open_issues,
  COUNT(*)                                            AS total_issues
FROM projects p
JOIN issues i ON i.project_id = p.id
WHERE p.target_date < CURRENT_DATE
  AND p.state <> 'completed'
GROUP BY p.name, p.target_date
HAVING COUNT(*) FILTER (WHERE i.state_type <> 'completed') > 0
ORDER BY p.target_date;
Bugs created vs. resolved per weekPostgreSQL

Quality trend; assumes a 'Bug' label via an issue_labels bridge table.

WITH bug_issues AS (
  SELECT i.*
  FROM issues i
  JOIN issue_labels il ON il.issue_id = i.id
  WHERE il.label = 'Bug'
)
SELECT
  weeks.week,
  COUNT(created.id)  AS bugs_created,
  COUNT(resolved.id) AS bugs_resolved
FROM (
  SELECT generate_series(
    date_trunc('week', CURRENT_DATE - INTERVAL '12 weeks'),
    date_trunc('week', CURRENT_DATE),
    INTERVAL '1 week'
  ) AS week
) weeks
LEFT JOIN bug_issues created
  ON date_trunc('week', created.created_at) = weeks.week
LEFT JOIN bug_issues resolved
  ON date_trunc('week', resolved.completed_at) = weeks.week
GROUP BY weeks.week
ORDER BY weeks.week;

What are common mistakes when analyzing Linear in Metabase?

Running dashboards off a one-time CSV export.→ Schedule the sync so data stays fresh — a manual export goes stale the moment someone acts on it.
Reporting straight off raw API/JSON tables.→ Add a thin model layer with consistent state_type and derived time metrics.
Measuring cycle time from created_at instead of started_at.→ Separate lead time (from created) and cycle time (from started); label charts clearly.
Using averages for cycle/lead time.→ Report medians and p90 — duration data is heavily right-skewed.
Comparing velocity across teams as if points are equivalent.→ Treat velocity as a within-team trend, not a cross-team leaderboard.
Ignoring canceled issues in completion math.→ Exclude state_type = 'canceled' from throughput and completion-rate denominators where appropriate.
Expecting historical flow from point-in-time snapshots.→ Capture state-change history if you need accurate WIP/aging over time.

Related dashboards

Related integrations

Related metrics