Metabase
Audited from github.com/metabase/metabase
Metabase is a self-hosted business intelligence tool: a Clojure and JVM backend (src/metabase) compiled to a single jar, paired with a TypeScript and React frontend built with Rspack, Mantine, and Redux Toolkit, plus a ClojureScript build and a Python-based SQL transform layer.
- Language
- Clojure
- Database
- PostgreSQL
- Hosting
- Docker
- Running for
- 9 years
- Team
- 20+ people
Why this architecture
Shipping the backend as one Clojure uberjar behind a bare JVM Docker image keeps self-hosting to a single artifact and runtime, while splitting SQL-dialect transform logic into a separate Python package lets that feature reuse an existing SQL-transpilation library instead of reimplementing it in Clojure.
Tech stack by layer
8 technologies · audited Sep 17, 2026- ReactComponent framework for the web app under frontend/src.
- MantineUI component library used across the application interface.
- Redux ToolkitApplication state management for the frontend.
- CodeMirrorPowers the native SQL editor, including SQL-specific language modes.
- RspackRust-based bundler that builds the production frontend assets.
- ClojureImplements the core application server under src/metabase, compiled to a single uberjar.
- JavaJVM runtime; the release image runs the compiled jar on eclipse-temurin:25-jre-alpine.
- ClojureScriptAdditional frontend logic compiled via shadow-cljs, alongside the TypeScript codebase.
- PythonPowers a SQL-transform feature via a separate Python package depending on sqlglot.
- PostgreSQLOne of the most prominently supported data warehouse connections, per repository topics.(inferred)
- MySQLAlso a prominently supported data warehouse connection, per repository topics.(inferred)
- CypressDrives the end-to-end test suite against a running instance.
- StorybookComponent development and visual review environment for the frontend.
- GitHub ActionsRuns the large multi-workflow CI/CD pipeline covering backend, frontend, e2e, and release automation.
Metabase architecture diagram
Open SVGDiagram as text
- Web app (React · Mantine · Redux) → Metabase server (Clojure uberjar · JVM): REST
- Embedding SDK (host apps) → Metabase server (Clojure uberjar · JVM): REST
- Metabase server (Clojure uberjar · JVM) → Application DB (settings · questions): metadata
- Metabase server (Clojure uberjar · JVM) → Your databases (Postgres · MySQL · …): native queries
- Metabase server (Clojure uberjar · JVM) → SQL transforms (Python · sqlglot): transforms
Key architectural decisions
6 decisions- 01
Backend is a single Clojure/JVM artifact, not microservices
src/metabase (Clojure) compiles to a single uberjar via bin/build.sh, and the Dockerfile runtime stage is a bare eclipse-temurin:25-jre-alpine image running that jar, so the whole backend ships as one deployable artifact rather than separate services.
- 02
Frontend build has moved onto Rspack instead of webpack
package.json devDependencies include @rspack/core, @rspack/cli, and @rspack/dev-server, a Rust-based webpack-compatible bundler, alongside @storybook/react-webpack5 for component development, so the production build and Storybook currently target different bundler configurations.
- 03
Bun manages frontend dependencies instead of npm or yarn
package.json declares bun >=1.0.0 as a required engine, and the root Dockerfile installs bun globally with npm install -g bun before running bun install --frozen-lockfile, so dependency installation is standardized on Bun even though the built output is ordinary JavaScript.
- 04
A Python transform layer sits alongside the Clojure core
resources/python-sources/pyproject.toml defines a separate Python package depending on sqlglot for SQL dialect parsing and transpilation, exercised by the transforms-python-stress-test.yml workflow, so cross-dialect SQL handling for the transforms feature runs in Python rather than Clojure.
- 05
The embedding SDK is tested against real host app frameworks
e2e/embedding-sdk-host-apps contains separate package.json projects for an Angular 20 app, two Next.js 15 variants (app router and pages router), and a Vite 6 app, each installing the embedding SDK, so compatibility is verified against real framework setups rather than one mocked host.
- 06
ClojureScript compiles alongside TypeScript, not instead of it
shadow-cljs.edn configures a ClojureScript build that coexists with the primary TypeScript and React frontend in frontend/src, so the client is built from two source languages rather than a single one.
How Metabase is built
How Metabase is structured
Metabase is a single repository combining a Clojure JVM backend and a JavaScript/TypeScript frontend. The backend lives in src/metabase and is described by deps.edn (Clojure's dependency and build tool config); bb.edn configures Babashka scripts used for project tooling. The frontend lives in frontend/src and is described by the root package.json, with an additional ClojureScript build configured in shadow-cljs.edn compiling alongside it. resources/python-sources holds a separate Python package (pyproject.toml) for the SQL transforms feature. e2e/embedding-sdk-host-apps contains standalone sample applications (Angular, two Next.js variants, Vite) used to test the embedding SDK against real host frameworks, and release/ and release/ci-conductor hold their own Node packages for release tooling, separate from the main frontend package.
Backend & APIs
The backend compiles from src/metabase into a single executable jar via bin/build.sh, invoked from the Dockerfile's builder stage after installing the Clojure CLI (linux-install-1.12.0.1488.sh) and a Temurin JDK. The production runtime, bin/docker/Dockerfile, is a minimal eclipse-temurin:25-jre-alpine image that copies in only metabase.jar and a run_metabase.sh launcher — there is no separate application server framework visible in the audited manifests, since Clojure/JVM web apps of this kind typically embed their own HTTP layer directly in the compiled jar. Both Docker images import AWS RDS (rds-combined-ca-bundle.pem) and Azure (DigiCertGlobalRootG2.crt.pem) certificate authorities into the JVM's trust store with keytool, which is direct evidence that Metabase is built to connect over TLS to managed PostgreSQL/MySQL instances hosted on those clouds as data sources or as its own application database.
Frontend
package.json shows a large, TypeScript-heavy single-page application: React 18 as the component framework, @reduxjs/toolkit plus react-redux, redux-actions, and redux-undo for state, and a substantial Mantine (@mantine/core, @mantine/dates, @mantine/hooks) and Emotion (@emotion/react, @emotion/styled) UI layer. The native query editor uses CodeMirror (@codemirror/lang-sql, @uiw/react-codemirror) with a custom Handlebars language mode (@xiechao/codemirror-lang-handlebars) for templated native queries. Visualizations combine d3, @visx/*, and echarts; @xyflow/react renders flow-style diagrams; @dnd-kit/* and react-grid-layout implement dashboard drag-and-drop and grid layout; and @tiptap/* powers rich-text editing (for example dashboard text cards). The frontend builds through @rspack/core/@rspack/cli rather than webpack directly, with @rspack/plugin-react-refresh for hot reloading, while @storybook/react-webpack5 still uses the webpack5 Storybook builder — a transitional state visible directly in the dependency list.
Data & persistence
Metabase's role as a BI tool is to connect to and query external databases rather than own a single fixed datastore; the driver system itself sits outside the top-level tree captured for this audit, but drivers.yml and drivers-stress-test.yml in .github/workflows confirm a dedicated, separately tested driver layer, and the certificate trust setup in both Dockerfiles (RDS and Azure CAs) shows first-class support for cloud-hosted PostgreSQL- and MySQL-family databases. Within the repository itself, resources/python-sources/pyproject.toml adds sqlglot as a dependency for a Python-based SQL transform capability, used to parse and rewrite SQL across dialects — a targeted use of an external, mature SQL-parsing library rather than reimplementing dialect handling in Clojure.
Build, test & deploy
package.json's engines field requires node >=22 and bun >=1.0.0; the Dockerfile builder stage installs Bun globally (npm install -g bun) and runs bun install --frozen-lockfile before invoking bin/build.sh, which in turn builds the Clojure jar and the frontend assets together for a given MB_EDITION (oss or enterprise). Testing spans several layers: cljs.yml and backend.yml/backend-cloverage.yml cover Clojure and ClojureScript, frontend.yml and frontend-unit-test-stress-test-flake-fix.yml cover the JS/TS unit tests, and a large e2e surface runs through Cypress (e2e-test.yml, e2e-tests.yml, e2e-matrix-builder.yml, e2e-coverage-manifest.yml/e2e-coverage-shard.yml) plus dedicated embedding-sdk-component-tests.yml and embedding-sdk-host-sample-apps-tests.yml workflows exercising the sample apps in e2e/embedding-sdk-host-apps. chromatic.yml runs visual regression against Storybook stories, and containerize-jar.yml/uberjar.yml/release.yml handle packaging and release.
Self-hosting notes
Self-hosting means running the compiled jar on a JVM (25, per both Dockerfiles) or the equivalent Docker image (bin/docker/Dockerfile, published from containerize-jar.yml), with connectivity to whichever external SQL databases are configured as data sources — the RDS/Azure certificate bundling in both Dockerfiles indicates first-class support for connecting to those specific managed database providers over TLS. Building from source additionally requires the Clojure CLI and Bun, as shown in the root Dockerfile's builder stage, rather than only a JDK. .devcontainer/Dockerfile provides a preconfigured development container so contributors do not need to install the JVM/Clojure/Bun toolchain manually on their host machine.
What to copy (and what not to)
Shipping the entire backend as one self-contained jar behind a minimal JRE-only Docker image (bin/docker/Dockerfile) is a strong pattern for a tool meant to be self-hosted by a wide range of operators: there is exactly one runtime dependency (a JVM) and one artifact to manage. Splitting a narrow, well-defined subproblem — SQL dialect transpilation for the transforms feature — into its own Python package that leans on an existing library (sqlglot) rather than reimplementing that logic in the primary language (Clojure) is a reasonable way to avoid maintaining a hard problem twice, though it does mean the deployment now needs a Python runtime alongside the JVM for that one feature. Running two frontend build toolchains at once (Rspack for the app, webpack5 for Storybook) is a visible in-progress migration rather than a settled decision, and teams copying this setup should expect to converge on one bundler rather than treat the split as a stable target.
Sources & repo audit
- Audited
- Sep 17, 2026
- Commit
- e28ae43
- License
- NOASSERTION
- package.json (React, Mantine, Redux Toolkit, Rspack, Bun engine requirement)
- Dockerfile (multi-stage JVM and Bun frontend build)
- bin/docker/Dockerfile (jar-only production runtime image)
- resources/python-sources/pyproject.toml (sqlglot dependency for SQL transforms)
- e2e/embedding-sdk-host-apps/next-15-app-router-host-app/package.json (embedding SDK host app test)
Independent analysis of repository at github.com/metabase/metabase. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/metabase)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Metabase's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Metabase" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Metabase**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Metabase
- **What It Does**: Metabase is a self-hosted business intelligence tool: a Clojure and JVM backend (src/metabase) compiled to a single jar, paired with a TypeScript and React frontend built with Rspack, Mantine, and Redux Toolkit, plus a ClojureScript build and a Python-based SQL transform layer.
- **Domain & Category**: Business Intelligence Platform
- **Production Scale**: 20+ people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Shipping the backend as one Clojure uberjar behind a bare JVM Docker image keeps self-hosting to a single artifact and runtime, while splitting SQL-dialect transform logic into a separate Python package lets that feature reuse an existing SQL-transpilation library instead of reimplementing it in Clojure.
- **Live Website Reference**: https://metabase.com
- **Source Repository**: https://github.com/metabase/metabase
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Clojure, ClojureScript, TypeScript, React, Java, Python, PostgreSQL, MySQL
- **Primary Language(s)**: Clojure, TypeScript, JavaScript
- **License of the reference repo**: NOASSERTION
- **Frontend**: React — Component framework for the web app under frontend/src.; Mantine — UI component library used across the application interface.; Redux Toolkit — Application state management for the frontend.; CodeMirror — Powers the native SQL editor, including SQL-specific language modes.; Rspack — Rust-based bundler that builds the production frontend assets.
- **Backend & APIs**: Clojure — Implements the core application server under src/metabase, compiled to a single uberjar.; Java — JVM runtime; the release image runs the compiled jar on eclipse-temurin:25-jre-alpine.; ClojureScript — Additional frontend logic compiled via shadow-cljs, alongside the TypeScript codebase.; Python — Powers a SQL-transform feature via a separate Python package depending on sqlglot.
- **Data & persistence**: PostgreSQL — One of the most prominently supported data warehouse connections, per repository topics.; MySQL — Also a prominently supported data warehouse connection, per repository topics.
- **Infrastructure & deploy**: Docker — Multi-stage build compiles the backend and frontend; a separate slim image serves the runtime jar.; Bun — Installs and manages frontend JavaScript dependencies during the build.
- **Tooling, testing & ops**: Cypress — Drives the end-to-end test suite against a running instance.; Storybook — Component development and visual review environment for the frontend.; GitHub Actions — Runs the large multi-workflow CI/CD pipeline covering backend, frontend, e2e, and release automation.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/metabase/metabase @ e28ae43)
1. **Backend is a single Clojure/JVM artifact, not microservices**: src/metabase (Clojure) compiles to a single uberjar via bin/build.sh, and the Dockerfile runtime stage is a bare eclipse-temurin:25-jre-alpine image running that jar, so the whole backend ships as one deployable artifact rather than separate services.
2. **Frontend build has moved onto Rspack instead of webpack**: package.json devDependencies include @rspack/core, @rspack/cli, and @rspack/dev-server, a Rust-based webpack-compatible bundler, alongside @storybook/react-webpack5 for component development, so the production build and Storybook currently target different bundler configurations.
3. **Bun manages frontend dependencies instead of npm or yarn**: package.json declares bun >=1.0.0 as a required engine, and the root Dockerfile installs bun globally with npm install -g bun before running bun install --frozen-lockfile, so dependency installation is standardized on Bun even though the built output is ordinary JavaScript.
4. **A Python transform layer sits alongside the Clojure core**: resources/python-sources/pyproject.toml defines a separate Python package depending on sqlglot for SQL dialect parsing and transpilation, exercised by the transforms-python-stress-test.yml workflow, so cross-dialect SQL handling for the transforms feature runs in Python rather than Clojure.
5. **The embedding SDK is tested against real host app frameworks**: e2e/embedding-sdk-host-apps contains separate package.json projects for an Angular 20 app, two Next.js 15 variants (app router and pages router), and a Vite 6 app, each installing the embedding SDK, so compatibility is verified against real framework setups rather than one mocked host.
6. **ClojureScript compiles alongside TypeScript, not instead of it**: shadow-cljs.edn configures a ClojureScript build that coexists with the primary TypeScript and React frontend in frontend/src, so the client is built from two source languages rather than a single one.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (PostgreSQL, MySQL): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Metabase
What is Metabase built with?
Metabase is a Clojure and JVM backend (src/metabase, deps.edn) compiled to a single uberjar, with a TypeScript and React frontend bundled by Rspack, a ClojureScript build alongside it (shadow-cljs.edn), and a Python-based SQL transform layer (resources/python-sources).
Does Metabase need a backend?
Yes, Metabase is the backend and application together: it is a self-contained JVM server, built into a jar and run under eclipse-temurin, that also serves its own web UI.
Can I self-host Metabase?
Yes. bin/docker/Dockerfile packages a pre-built metabase.jar behind eclipse-temurin:25-jre-alpine, and the root Dockerfile documents a full from-source multi-stage build using the Clojure CLI, JDK 25, and Bun for frontend assets.
What frontend stack does Metabase use?
Metabase's frontend is React with TypeScript, Mantine for UI components, Redux Toolkit for state, CodeMirror for the native SQL editor, and Rspack as the bundler, with dependencies installed via Bun per package.json.
Does Metabase run on databases other than the one it stores its own metadata in?
The repository ships dedicated driver-related CI workflows (drivers.yml, drivers-stress-test.yml) and bundles AWS RDS and Azure certificate trust stores into its Docker images, consistent with Metabase connecting to many external SQL databases as data sources, though individual driver implementations sit outside the audited top-level tree.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- PenpotClassicDesign & Prototyping Platform · 20+ peopleShares Clojure · ClojureScript · TypeScript
- KestraClassicDeclarative Orchestration & Data Flow Engine · 6-20 peopleShares Java · TypeScript · PostgreSQL
- GrafanaClassicMonitoring & Observability Dashboard · 20+ peopleShares TypeScript · React · PostgreSQL
- SentryClassicError Tracking Platform · 20+ peopleShares Python · React · TypeScript
- PostHogHybridProduct Analytics Platform · 20+ peopleShares Python · React · TypeScript
- UmamiHybridWeb Analytics · SoloShares TypeScript · React · PostgreSQL