Running Metabase in production: upgrades, access and performance
A controlled dashboard load improved from about 49.7 seconds to 3.1 seconds after a metadata index change, alongside safer data access and operational backups.
A controlled production load improved from ~49.7 s to ~3.1 s; a separate MongoDB filter bottleneck remained.
Contribution at a glance
- My responsibility
- Upgrades, read-only database access and metadata-query performance diagnosis.
- Scope
- BI operations and a controlled production dashboard-load measurement.
- Collaboration & boundaries
- I isolated infrastructure and metadata bottlenecks; a separate MongoDB filter bottleneck remained outside the measured fix.
- Outcome
- Controlled dashboard load improved from ~49.7 s to ~3.1 s; this is not a universal dashboard-performance guarantee.
A BI tool quietly accumulates risk. It sits on powerful database credentials, its dashboards get slower as data grows, and its version drifts behind until an upgrade feels scary. I treated keeping Metabase healthy as three ongoing jobs: stay current, hold least privilege, and keep queries fast.
Stay current, environment by environment
I kept Metabase on supported versions rather than letting it rot, upgrading through several minor releases across environments and planning each bump instead of jumping blind. Routine, but it is the routine that stops a one-day upgrade from becoming a one-week one.
Least privilege: a BI tool should only read
Metabase connects to the databases it visualizes, and it is tempting to hand it a broad user because that "just works". That broad user is also a standing risk: a reporting tool with write access to source data is an incident waiting to happen. I replaced the broad database users with a dedicated read-only user, so the BI layer can query everything it needs and change nothing. A visualization tool has no business being able to write.
Keep production out of the blast radius
Heavy analytical queries and live production traffic do not belong on the same database node. I mapped every data source Metabase was reading from and found queries landing on the primary, competing with the application. I routed those reads to a dedicated analytics replica instead, to reduce contention with the product workload.
Find the metadata bottleneck
A slow dashboard investigation showed that each card spent much of its time fetching metadata from Metabase's own application database, before querying the source data. Dynamic source fields had accumulated a large metadata table; the existing index did not match the filter on table and active status.
I reproduced the exact SQL on a disposable clone, compared sequential and concurrent loads, and rehearsed index creation and rollback. In production, I took a fresh backup, waited for active queries to clear and added a composite index with an explicit lock timeout and online DDL.
| Signal | Before | After |
|---|---|---|
| Metadata SQL, EXPLAIN ANALYZE | 4,356 ms | 8.2 ms |
| Eight cards, each | 35.7–37.1 s | 1.15–1.62 s |
| Whole dashboard tab | ~49.7 s | ~3.1 s |
Index creation took about 29 seconds with zero metadata-lock waits in that execution. These are controlled before/after measurements, not a latency distribution for all dashboard users. A separate MongoDB filter scan remained a different bottleneck, and the originally reported 524 did not have a proven cause.
The follow-up confirmed a successful automated daily backup with seven retained recovery points. Temporary clone resources and approved on-demand backups were cleaned up. The index was added to the upgrade checklist because it sits outside Metabase's own migrations and must be checked after an upgrade or restore.
Also: trust the data, not just the tool
A separate but related job is data freshness. When a dashboard quietly stopped updating for one downstream integration, the tool looked fine; the data had gone stale upstream. Operating a BI platform well means watching the pipeline into it, not only the service itself, because a confidently-wrong dashboard is worse than a broken one.
What I would tell someone running a BI tool
- Give it a read-only user. A reporting tool should never be able to write to source data.
- Point analytical reads at a replica. Keep heavy dashboards off the node that serves the product.
- Index for the query. Trace metadata loading separately from source queries, then test the index against the exact SQL.
- Watch the data in, not just the service. A stale dashboard that still renders is the quiet failure mode.
- Upgrade on a schedule. Staying a few minors behind is cheaper than catching up by years.
Decisions and next steps
A retrospective view of the approach and its limits. The next improvement is a proposal, not a delivered result.
Alternative and rationale
Adding database capacity is one option; profiling first exposed a metadata access pattern that could be addressed with an index.
Trade-off
Index changes need a backup, a disposable rehearsal and a rollback plan. Metadata and source-query latency are different bottlenecks.
What I would improve next
Next improvement: repeat representative dashboard tests over time and address the remaining source-query bottleneck separately.