Overview
Metabase is an open-source business intelligence tool that enables anyone in an organization to ask questions about their data and get answers in the form of charts, dashboards, and reports. It features an intuitive visual query builder that allows non-technical users to explore data without writing SQL, while also providing a powerful native query editor for analysts and engineers who prefer SQL.
Metabase connects to virtually any SQL database including PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, MongoDB, and many others. It supports interactive dashboards with filters, drill-down capabilities, and auto-refresh. Metabase also offers embedded analytics for integrating dashboards into other applications, scheduled reports via email or Slack, and a question-based permissions model. The platform can be self-hosted or used via Metabase Cloud.
Installation
Docker (Recommended)
# Quick start with Docker
docker run -d \
--name metabase \
-p 3000:3000 \
metabase/metabase:latest
# With PostgreSQL application database (production)
docker run -d \
--name metabase \
-p 3000:3000 \
-e MB_DB_TYPE=postgres \
-e MB_DB_DBNAME=metabase \
-e MB_DB_PORT=5432 \
-e MB_DB_USER=metabase \
-e MB_DB_PASS=metabase_pass \
-e MB_DB_HOST=postgres-host \
metabase/metabase:latest
# Access at http://localhost:3000
Docker Compose
version: '3.8'
services:
metabase:
image: metabase/metabase:latest
container_name: metabase
ports:
- "3000:3000"
environment:
MB_DB_TYPE: postgres
MB_DB_DBNAME: metabase
MB_DB_PORT: 5432
MB_DB_USER: metabase
MB_DB_PASS: metabase_pass
MB_DB_HOST: metabase-db
MB_SITE_URL: https://metabase.example.com
MB_ENCRYPTION_SECRET_KEY: your-secret-key-here
depends_on:
- metabase-db
restart: unless-stopped
metabase-db:
image: postgres:16
environment:
POSTGRES_DB: metabase
POSTGRES_USER: metabase
POSTGRES_PASSWORD: metabase_pass
volumes:
- metabase-pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
metabase-pgdata:
JAR Installation
# Download JAR
wget https://downloads.metabase.com/v0.49.0/metabase.jar
# Run (requires Java 11+)
java -jar metabase.jar
# Run with custom port and config
MB_JETTY_PORT=8080 \
MB_DB_TYPE=postgres \
MB_DB_HOST=localhost \
MB_DB_PORT=5432 \
MB_DB_DBNAME=metabase \
MB_DB_USER=metabase \
MB_DB_PASS=password \
java -jar metabase.jar
Kubernetes with Helm
helm repo add metabase https://pmint93.github.io/metabase-chart
helm install metabase metabase/metabase \
--namespace analytics \
--create-namespace \
--set database.type=postgres \
--set database.host=postgres.default.svc
Database Connections
Supported Databases
| Database | Driver | Connection String |
|---|
| PostgreSQL | Built-in | host:5432/dbname |
| MySQL | Built-in | host:3306/dbname |
| BigQuery | Built-in | Project ID + Service Account JSON |
| Snowflake | Built-in | account.snowflakecomputing.com |
| Redshift | Built-in | cluster.region.redshift.amazonaws.com:5439/db |
| MongoDB | Built-in | mongodb://host:27017/db |
| SQLite | Built-in | /path/to/database.db |
| SQL Server | Built-in | host:1433;database=db |
| ClickHouse | Plugin | host:8123/database |
| DuckDB | Plugin | /path/to/database.duckdb |
| Trino/Presto | Plugin | host:8080/catalog |
Adding a Database via API
curl -X POST http://localhost:3000/api/database \
-H "Content-Type: application/json" \
-H "X-Metabase-Session: $SESSION_TOKEN" \
-d '{
"engine": "postgres",
"name": "Production DB",
"details": {
"host": "db.example.com",
"port": 5432,
"dbname": "production",
"user": "readonly_user",
"password": "password",
"ssl": true,
"tunnel-enabled": false
}
}'
API Reference
Authentication
# Get session token
SESSION=$(curl -s -X POST http://localhost:3000/api/session \
-H "Content-Type: application/json" \
-d '{"username": "admin@example.com", "password": "password"}' \
| jq -r '.id')
# Use token in requests
curl -H "X-Metabase-Session: $SESSION" http://localhost:3000/api/card
Common API Endpoints
| Endpoint | Method | Description |
|---|
/api/session | POST | Login and get session token |
/api/card | GET | List all saved questions |
/api/card | POST | Create a new question |
/api/card/{id} | GET | Get question details |
/api/card/{id}/query | POST | Execute a question |
/api/dashboard | GET | List all dashboards |
/api/dashboard | POST | Create a dashboard |
/api/dashboard/{id} | GET | Get dashboard details |
/api/database | GET | List databases |
/api/collection | GET | List collections |
/api/dataset | POST | Execute an ad-hoc query |
/api/user | GET | List users |
/api/alert | GET | List alerts |
/api/pulse | GET | List subscriptions |
Execute Custom Query
# Run SQL query via API
curl -X POST http://localhost:3000/api/dataset \
-H "Content-Type: application/json" \
-H "X-Metabase-Session: $SESSION" \
-d '{
"database": 1,
"type": "native",
"native": {
"query": "SELECT DATE_TRUNC('\''month'\'', created_at) AS month, COUNT(*) AS orders FROM orders GROUP BY 1 ORDER BY 1"
}
}'
Configuration
Environment Variables
| Variable | Description | Default |
|---|
MB_DB_TYPE | Application database type | h2 |
MB_DB_HOST | Database host | localhost |
MB_DB_PORT | Database port | varies |
MB_DB_DBNAME | Database name | metabase |
MB_DB_USER | Database user | metabase |
MB_DB_PASS | Database password | |
MB_JETTY_PORT | HTTP port | 3000 |
MB_SITE_URL | Public-facing URL | http://localhost:3000 |
MB_ENCRYPTION_SECRET_KEY | Encryption key for DB secrets | |
MB_EMAIL_SMTP_HOST | SMTP server for emails | |
MB_EMAIL_SMTP_PORT | SMTP port | 587 |
MB_EMAIL_FROM_ADDRESS | Sender email address | |
MB_EMBEDDING_SECRET_KEY | Key for embedding tokens | |
MB_ENABLE_EMBEDDING | Enable embedding | false |
MB_PREMIUM_EMBEDDING_TOKEN | Pro/Enterprise license key | |
JAVA_OPTS | JVM options | -Xmx2g |
Email Configuration
docker run -d \
--name metabase \
-p 3000:3000 \
-e MB_EMAIL_SMTP_HOST=smtp.gmail.com \
-e MB_EMAIL_SMTP_PORT=587 \
-e MB_EMAIL_SMTP_SECURITY=tls \
-e MB_EMAIL_SMTP_USERNAME=your@gmail.com \
-e MB_EMAIL_SMTP_PASSWORD=app-password \
-e MB_EMAIL_FROM_ADDRESS=analytics@yourcompany.com \
metabase/metabase:latest
Advanced Usage
Embedded Analytics
<!-- Embedding a dashboard using iframe (signed JWT) -->
<iframe
src="http://metabase.example.com/embed/dashboard/TOKEN"
frameborder="0"
width="100%"
height="800"
allowtransparency
></iframe>
# Generate embedding token (server-side)
import jwt
import time
METABASE_SITE_URL = "http://metabase.example.com"
METABASE_SECRET_KEY = "your-embedding-secret-key"
payload = {
"resource": {"dashboard": 1},
"params": {"customer_id": 42},
"exp": round(time.time()) + (10 * 60) # 10 min expiry
}
token = jwt.encode(payload, METABASE_SECRET_KEY, algorithm="HS256")
iframe_url = f"{METABASE_SITE_URL}/embed/dashboard/{token}#bordered=true&titled=true"
Custom SQL with Variables
-- Filter variable (dropdown)
SELECT * FROM orders
WHERE status = {{status}}
-- Text variable
SELECT * FROM products
WHERE name ILIKE '%' || {{search_term}} || '%'
-- Date range variable
SELECT * FROM orders
WHERE created_at BETWEEN {{start_date}} AND {{end_date}}
-- Optional filter clause
SELECT * FROM orders
[[WHERE category = {{category}}]]
-- Field filter (smart filter)
SELECT * FROM orders
WHERE {{created_at}}
Backup and Restore
# Backup application database (H2)
cp /path/to/metabase.db.mv.db /backups/metabase-$(date +%Y%m%d).db.mv.db
# Backup PostgreSQL app DB
pg_dump -h localhost -U metabase metabase > metabase_backup.sql
# Restore
psql -h localhost -U metabase metabase < metabase_backup.sql
Troubleshooting
| Issue | Solution |
|---|
| Slow dashboard loading | Enable caching in Admin > Performance. Optimize underlying SQL queries |
| Database connection timeout | Check firewall rules. Increase connection timeout in database settings |
| Out of memory | Increase JAVA_OPTS=-Xmx4g. Use PostgreSQL instead of H2 for app database |
| Embedding not working | Verify MB_ENABLE_EMBEDDING=true. Check JWT token expiry and secret key |
| Email alerts not sending | Verify SMTP configuration. Check Metabase logs for email errors |
| Permission issues | Check collection permissions. Verify data model permissions for tables |
| H2 database corruption | Migrate to PostgreSQL for production. Restore from latest backup |
| SSL connection errors | Add ssl=true to database connection. Import CA certificates if needed |
| Dashboard filter not working | Verify filter is connected to cards. Check field mapping in filter config |
| API rate limiting | Increase rate limits in admin settings. Use API keys for automation |