Vibe code your own Metabase
Vibe code your own Metabase as one saved SELECT and a result table. The query builder, row permissions, and warehouse sync are the hard half.
You can vibe code your own Metabase as one saved SELECT and a result table. Metabase is that product. The catalog line is “Type a SELECT. Save it. Open the same table tomorrow.”
The card prices Starter at $100 a month through Pro at $575. Yearly billing is $90 a month ($1,080 a year) and $517.50 a month ($6,210 a year). Starter adds $6 a user a month after five users. Pro adds $12 after ten. That note leaves out the open source edition and Enterprise quotes. The first estimate is 12 hours.
Last time I wrote about building a Luma alternative. That was a regular backlog post. This one is a teardown.
Vibe code your own Metabase as a saved question
The Metabase page splits the work into three rows.
The first row is 12 hours. One database, a saved SELECT, a result table. You connect a read-only Postgres role, run one statement, and keep the SQL under a name.
The second row is 4 days. A dashboard, a date filter, and a bar chart. Same questions, arranged on one page, with a filter that changes the window.
The third row is a month and up. A click query builder, row permissions, and many databases. Skip that row.
If you tell an agent to “clone Metabase”, it aims at the third row. Copy the prompt, then pin it to the first one.
Store a connection, a question, and a result summary. The board lists questions with the latest row count.
A connection holds host, database, user, and a password that stays on the server. A question holds a name and the SQL text. A result on the board is a row count and a runtime. The rows themselves stay in Postgres.
The audience is one analyst running the same read-only questions against one Postgres database. The verdict on the card is “Save the question”. A typed table you edit by hand is Airtable at $24–$54 a person a month, covered in Build an Airtable alternative. An approval screen is Retool at $12–$65 a person a month, covered in Build a Retool alternative. Named events are Mixpanel at $140–$2,289 a month.
How does Metabase work
Metabase publishes two databases in Configuring the application database. I am summarizing that page, the sync and scan docs, the data permissions docs, the SQL editor docs, the driver guide, and the public query processor. Where those pages stop, I call it a guess.
The application database stores users, questions, dashboards, and the rest of the app. The warehouse is a second database. They recommend PostgreSQL for production. H2 is the file they ship for a local demo, and the same page says to avoid it in production. Metabase reads that connection at startup. You cannot swap it while the process is running.
The warehouse is the database you ask questions about. Connecting it is a second configuration. A 12-hour clone has one of those, a read-only Postgres role, and nothing else.
Questions come in two shapes. The visual query builder produces MBQL, Metabase’s own query language. The driver guide says the query processor compiles MBQL into a native query, then executes it. The SQL editor is the other shape. Its docs say Metabase sends that SQL to your database exactly as it is written. Results and errors match what the database would return on its own.
The query processor source splits a run into preprocess, compile, execute, and postprocess. A userland query catches errors, writes a QueryExecution into the application database, and applies default limits. The middleware names move with the source tree, so a fixed list of them is a guess.
The SQL editor docs leave out multi-statement queries, stored procedures, and DDL such as CREATE or DROP. On databases that use impersonation, they enforce a single SELECT. A broad role can still do more, and their page says not to use the editor for that. The catalog guardrail is stricter on purpose. One statement, it has to start with SELECT, and a write or a second statement never leaves the app.
Permissions are a second product. The data permissions page says View data options, including row and column security, ship on Pro and Enterprise. In the open source build, View data stays on “Can view” and those options are hidden. Create queries can allow the SQL editor, or the builder only.
They also document a limit that matters if you try to copy the permission graph. Metabase does not parse SQL. Block one table and a group loses native questions against every table in that database, because the app cannot prove the SQL avoided the blocked table. The same rule turns native queries off when any table is under row and column security. Builder questions can be checked, because MBQL names tables. Raw SQL has no table list to check.
Sync is the background work. A lightweight schema sync runs hourly by default, and a heavier value scan runs daily. Sync cannot be turned off, or the app would not know the tables. The sync query they publish is SELECT TRUE ... WHERE 1 <> 1 LIMIT 0 against each table, used to read names and types. Scans cache dropdowns from the first 1,000 distinct values, keeping the first 100 kilobytes of each. Fingerprinting reads the first 10,000 rows for stats such as null ratio, min, and max, and by default that runs only when you first connect. Later scans stick to fields someone used in the last fourteen days.
A v1 does none of that sampling. You type the SQL you already trust.
Node.js plus Astro is the default for the app. Use TanStack Start if React is your weekday language. The card’s stack is Astro, HTMX, and D1. D1 is the right place for the question text and the connection record, because those rows are small and owned by one analyst. The warehouse stays the Postgres you already run. HTMX can swap the result table without a second frontend.
Screens of a Metabase alternative
v1 needs the connection, the question, and the board.
Connection
The connection screen is host, database name, user, and a password field. Test runs a read and reports success or the database error. After save, the password is not rendered again. Logs may keep the question id, the runtime, and the row count. They must not keep the password or the result rows. That rule is on the card.
Question
The question screen is a SQL box, a run button, and a table. The header shows the row count, the runtime, and whether the cap cut the result. Saving stores the text you typed. Opening it later shows that text, not a rewritten query. An INSERT is refused in the app and is not sent.
Saved questions
Home is the board. Each row is a name, the last runtime, and the last row count. Open runs the stored SQL again. A chart, a date filter, and a dashboard layout wait on the 4-day row.
How a saved Metabase question runs
You save the connection and press test. The app checks the role with a read and stores the password on the server. You paste a SELECT and press run. Anything else stops before Postgres sees it. The page shows the rows and records the count and the runtime.
You name the question. The next morning the board lists “Pro accounts” with that count. Open loads the stored text and runs it again. The SQL on screen matches the row in D1.
An INSERT is rejected beside the box. The warehouse stays unchanged. A second statement after a semicolon gets the same refusal.
The hard half of a Metabase alternative
The skip row starts when the box has to serve people who do not write SQL, and people who must not see every row.
The query builder is that product. Clicks become MBQL, and the processor compiles MBQL per database driver. Joins, time bucketing, and nested questions fall out of that language. A 12-hour clone stores a string. Their driver guide is the map of the compiler.
Row and column security is paid, on Pro and Enterprise. It can limit rows from a user attribute, or swap in a custom view, per table. Impersonation, on the same tier, makes Metabase use a database role so the warehouse enforces the grant. Because SQL is not parsed, one restricted table disables native questions for the whole database. Hiding tables in the browser misses that case. The card parks row permissions on the month row.
Sync is the load you add so the builder can fill dropdowns and suggest charts. Hourly metadata queries, a daily scan of up to 1,000 distinct values, and a 10,000-row fingerprint are modest on a small Postgres and rude on a large one. Their docs let you scan only when someone adds a filter, or only by hand, because of that cost. A saved SELECT does not need those jobs.
Many databases means many drivers. The month row names that beside the builder. One read-only Postgres is the 12-hour row.
The non-goal on the card says not to write or update rows. Retool already covers an approval. Airtable already covers a table you edit yourself.
Start with the first row
Go to Build your own Metabase. Copy the Astro prompt, or TanStack Start if that is what you write.
Tell the agent the first estimate only. One database, a saved SELECT, a result table. Twelve hours.
If the question is a handful of named events, look at Mixpanel before you build a SQL box. If you need the click builder and row-level grants for a company, keep the paid Metabase plan, or run their open source edition and accept the limits their permissions page describes.