How do you build GitLab analytics dashboards in Metabase?
GitLab holds your merge requests, approvals, commits, CI/CD pipelines, and deployments. Metabase turns that into shared engineering dashboards. Metabase reads SQL databases — there's no native GitLab connector — so durable DORA and velocity dashboards start with a sync. For the engineering picture across tools, see the software delivery analytics overview; for the GitHub equivalent, see GitHub.
How do you connect GitLab to Metabase?
Most teams combine these: use the MCP route to explore and answer one-off questions, then build durable, warehouse-backed dashboards for anything you track over time. Setup for both MCP servers is below.
Live, conversational lookups
Pair a GitLab MCP server with the Metabase MCP server.
- Ad-hoc questions ("which MRs are waiting on approval?")
- Exploration before modeling
- Exploratory only — not governed reporting; no history
- API rate limits and project access scopes apply
- OAuth scopes on GitLab.com are still stabilizing — verify against current docs.
Durable DORA & velocity dashboards
Sync GitLab into a database (Airbyte, Fivetran, dlt, or the REST API), then point Metabase at it.
- Durable DORA dashboards, historical trends
- Joining MRs with pipelines, deploys, and issues
- You maintain the sync and model
- Self-managed vs. SaaS API differences need care
How do you use the GitLab and Metabase MCP servers together?
Pair the GitLab MCP server with the Metabase MCP server for live, conversational analysis. The GitLab MCP pulls current merge-request, approval, and pipeline data; the Metabase MCP queries the models and dashboards you've already built.
Example workflows
- List MRs waiting on approval, then summarize by group.
- Pull a project's failed pipelines from GitLab and cross-check against a Metabase CI model with the Metabase MCP.
- Draft a SQL question in Metabase from a natural-language ask, using GitLab MCP output to confirm field meanings.
- Triage: "show open MRs older than 7 days with no approval" straight from GitLab — 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 and DORA analysis still needs synced data in a database.
- Respect GitLab API rate limits and project access scopes.
- OAuth scopes on GitLab.com are still stabilizing — verify against current GitLab docs before you ship.
- The Metabase MCP server is built in; an admin enables it under Admin → AI → MCP.
How do you set up the GitLab and Metabase MCP servers?
GitLab MCP official
- Endpoint
https://gitlab.com/api/v4/mcp(self-managed:https://<your-gitlab>/api/v4/mcp)- Transport
- HTTP (or stdio via
mcp-remote) - Auth
- OAuth 2.0 Dynamic Client Registration (browser)
- Note
- Ships with GitLab (Duo) — there's no separate install on SaaS.
Metabase MCP built-in
- Enable
- Admin → AI → MCP
- Endpoint
https://<your-metabase>/api/metabase-mcp- Auth
- OAuth handled by Metabase
# GitLab (remote, OAuth in browser) — swap the host for self-managed
claude mcp add --transport http gitlab https://gitlab.com/api/v4/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 gitlab --url https://gitlab.com/api/v4/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.gitlab]
url = "https://gitlab.com/api/v4/mcp"
[mcp_servers.metabase]
url = "https://your-metabase.example.com/api/metabase-mcp"{
"mcpServers": {
"gitlab": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://gitlab.com/api/v4/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.
What can you analyze from GitLab data in Metabase?
- MR throughput — merge requests opened vs. merged per week, by project and group
- MR cycle time & lead time — created → first approval → merge → deploy
- Review health — time to first approval, approval latency, MRs merged without review, approver load
- Pipeline reliability — CI pipeline success rate, duration, repeatedly failing jobs
- Deployment frequency (DORA) — production deploys per day/week
- Change failure rate & MTTR (DORA) — failed deploys and time to restore
- Contributor activity — commits, active contributors, review participation
- Stale & WIP — aging open MRs, oldest drafts
Which GitLab dashboards should you build in Metabase?
- Engineering velocity — MR throughput and cycle time → see software delivery.
- Review health — time-to-first-approval, approval latency, unreviewed merges, approver load.
- Pipeline reliability — CI success rate and median pipeline duration, worst-offending jobs.
- DORA metrics — deployment frequency, lead time for changes, change failure rate, MTTR.
How should you model GitLab data in Metabase?
Map GitLab's objects to a clean model (don't report off raw connector tables):
| Table | Grain | Key columns |
|---|---|---|
merge_requests | one row per MR | id, iid, project_id, author_id, state, target_branch, source_branch, created_at, merged_at, closed_at |
mr_approvals | one row per approval | merge_request_id, user_id, approved_at |
pipelines | one row per CI pipeline | id, project_id, ref, status, created_at, finished_at, duration |
deployments | one row per deploy | id, project_id, environment, sha, status, created_at |
projects | one row per project | id, path, group, default_branch, archived |
commits | one row per commit | sha, project_id, author_id, committed_at |
users | one row per account | id, username, bot |
- Flag bot/service accounts (
bot) and exclude them from contributor metrics. - Restrict merge/flow analysis to each project's
default_branch— don't count every branch. - Derive cycle time from
created_at → merged_atand approval latency from the firstmr_approvals.approved_at. - Join
deploymentstocommits/MRs byshato compute lead time for changes.
Can you generate a GitLab dashboard with AI?
Yes. Use this prompt with the Metabase MCP server plus an assistant that can read your warehouse schema:
Create a Metabase dashboard called "GitLab Engineering Health & DORA" from the
synced GitLab tables in this database. Inspect the schema first; do not assume
table names. Map raw tables to: merge_requests, mr_approvals, pipelines,
deployments, projects, commits, users. Filter out bot/service accounts and
restrict merge analysis to each project's default branch.
Sections: (1) Velocity — MRs opened vs merged per week, by project and group;
(2) Flow — median MR cycle time (created to merged) by week, p90, open-MR age;
(3) Review health — median time to first approval, share of MRs merged without
review, approver load; (4) DORA — deployment frequency, lead time for changes,
change failure rate, and MTTR; (5) CI — pipeline success rate and median
pipeline duration.
Only compute change failure rate and MTTR if deployment outcomes or linked
incidents exist; otherwise add a caveat. Build durable questions from database
tables, treat MCP as exploratory, and do not claim a native GitLab connector.
Add filters for project, group, author, branch, and date range.What SQL powers GitLab dashboards in Metabase?
SELECT
date_trunc('week', mr.merged_at) AS week,
COUNT(*) AS merged_mrs,
percentile_cont(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (mr.merged_at - mr.created_at)) / 3600
) AS median_cycle_hours
FROM merge_requests mr
WHERE mr.merged_at IS NOT NULL
AND mr.target_branch = 'main'
GROUP BY 1
ORDER BY 1;SELECT
date_trunc('week', d.created_at) AS week,
COUNT(*) AS deployments,
COUNT(DISTINCT d.project_id) AS projects_deployed
FROM deployments d
WHERE d.environment = 'production'
AND d.status = 'success'
GROUP BY 1
ORDER BY 1;SELECT
date_trunc('week', p.created_at) AS week,
COUNT(*) AS pipelines,
AVG((p.status = 'success')::int) AS success_rate
FROM pipelines p
WHERE p.ref = 'main'
GROUP BY 1
ORDER BY 1;What are common mistakes when analyzing GitLab in Metabase?
mr_approvals.approved_at, not merged_at.