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. This guide covers two complementary paths: a lightweight MCP route for fast, AI-assisted questions, and a durable pipeline route that syncs Linear into a database or warehouse so you can build dashboards anyone can read.
How do you connect Linear to Metabase?
Most teams combine these: use the MCP route to explore and answer one-off questions, and the pipeline route for the dashboards people depend on.
Live, conversational analysis
Pair the Linear MCP server with the Metabase MCP server so an AI assistant can pull live issue data and query existing Metabase models on demand.
- Ad-hoc questions you don't want to model yet
- Exploring what's worth tracking before you build
- Spot checks like "which projects slipped this cycle?"
- Not a substitute for governed or scheduled reporting
- Answers depend on the assistant and API rate limits
- No history unless your data already lives in Metabase
Durable dashboards with history
Sync Linear into a database or warehouse with Airbyte, Fivetran, dlt, or the GraphQL API, then point Metabase at it.
- Dashboards the whole team relies on
- Historical trends (velocity over quarters, cycle time drift)
- Joining Linear with GitHub, deploys, or support data
- Requires a destination database and a sync to maintain
- Some connector sources may be community-maintained — verify
- You own the data model and refresh schedule
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?
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)
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)
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)
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 use the Linear and Metabase MCP servers together?
Pair the Linear MCP server with the Metabase MCP server for live, conversational analysis. The Linear MCP pulls current issue/project data; the Metabase MCP queries the models and dashboards you've already built.
Example workflows
- List issues completed in the current cycle via the Linear MCP, then summarize by team.
- Pull a project's open issues from Linear and cross-check progress against a Metabase model with the Metabase MCP.
- Draft a SQL question in Metabase from a natural-language ask, using Linear MCP output to confirm field meanings.
- Triage: "show high-priority bugs with no assignee created this week" straight from Linear — no dashboard required.
Be honest about the limits
- MCP is great for live lookups — not for scheduled or audited reporting.
- It does not create history; trend analysis still needs synced data in a database.
- Respect Linear API rate limits and access scopes for the connected workspace.
- The Metabase MCP server is built in; an admin enables it under Admin → AI → MCP.
How do you set up the Linear and Metabase MCP servers?
Linear MCP official
- Endpoint
https://mcp.linear.app/mcp- Transport
- Streamable HTTP
- Auth
- OAuth 2.1 (browser) — no API key, no local install
- Note
- The
/sseendpoint is deprecated.
Metabase MCP built-in
- Enable
- Admin → AI → MCP
- Endpoint
https://<your-metabase>/api/metabase-mcp- Auth
- OAuth handled by Metabase
# Linear (remote, OAuth in browser)
claude mcp add --transport http linear https://mcp.linear.app/mcp
# Metabase built-in MCP (replace with your instance URL)
claude mcp add --transport http metabase https://your-metabase.example.com/api/metabase-mcpClaude Desktop: add each as a remote/custom connector (Settings → Connectors) using the same URLs; Claude handles the OAuth pop-up.
codex mcp add linear --url https://mcp.linear.app/mcp
codex mcp add metabase --url https://your-metabase.example.com/api/metabase-mcpFirst remote MCP in Codex? Enable the rmcp client in ~/.codex/config.toml:
[features]
experimental_use_rmcp_client = true
[mcp_servers.linear]
url = "https://mcp.linear.app/mcp"
[mcp_servers.metabase]
url = "https://your-metabase.example.com/api/metabase-mcp"{
"mcpServers": {
"linear": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.linear.app/mcp"]
},
"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. On first connection each server opens a browser window to authorize.
Can you generate a Linear dashboard with AI?
Yes — and this is the fastest way to a strong first draft. Use the prompt below with the Metabase MCP server, Codex, Claude, Cursor, or any other assistant that can inspect your warehouse schema and create Metabase questions. It assumes Linear data is already synced into a database Metabase can read. It deliberately treats MCP as exploratory and builds the durable dashboard from database tables — and tells the agent to skip metrics the schema can't support instead of faking them.
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:
- Treat MCP data access as exploratory only.
- Build the dashboard 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 do you sync Linear data into a database or warehouse?
For dashboards that need history and reliability, land Linear data in a database first, then connect Metabase to that database.
Connector options
- Airbyte(managed ETL) — has a Linear source connector. Syncs issues, projects, teams, and related entities; check Airbyte docs for the current stream list.
- Fivetran(managed ETL) — does not offer a native Linear connector; use Airbyte, dlt, or the GraphQL API instead.
- dlt(code) — write a small Python pipeline against Linear's GraphQL API; best for full control of streams and schema.
- Linear GraphQL API(raw) — the source of truth; paginate issues/cycles/projects and upsert on a schedule.
Recommended destinations
- Postgres — simple, great for small/medium teams
- BigQuery / Snowflake / Redshift — scales, easy joins with 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.
How should you model Linear data in Metabase?
Core tables
| Table | Grain | Key columns |
|---|---|---|
issues | one row per issue | id, identifier, team_id, project_id, cycle_id, state_type, priority, estimate, assignee_id, created_at, started_at, completed_at, canceled_at |
cycles | one row per cycle | id, team_id, number, starts_at, ends_at |
projects | one row per project | id, name, state, target_date, started_at, completed_at, lead_id |
teams | one row per team | id, name, key |
users | one row per member | id, name, email, active |
Modeling advice
- Add derived
cycle_time = completed_at - started_atandlead_time = completed_at - created_atin your model layer, not in every question. - Normalize state into a small
state_typeset (backlog/started/completed/canceled) so charts stay stable when workflow states change. - If you need historical WIP/flow, model an
issue_state_historytable 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?
| Metric | Definition | Notes |
|---|---|---|
| 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 time | completed_at − started_at, usually a median. | Use median (p50) and p90; averages are skewed by outliers. |
| Lead time | completed_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 rate | Share of issues started in a cycle but completed later. | Signals over-commitment or scope churn. |
| Bug ratio | Completed bug issues ÷ all completed issues. | Watch the trend, not a single number. |
| Estimation accuracy | Relationship 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.
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;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;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 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;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?
state_type and derived time metrics.state_type = 'canceled' from throughput and completion-rate denominators where appropriate.