Back to blog
July 9, 2026Product7 min read

Headless BI: Rent the Engine, Own the Frontend

Classic embedded analytics locks you into a vendor's iframe. Headless BI flips it: own your dashboard code, rent the hard part — the ETL and query engine. The shadcn-meets-Supabase model for analytics.

V
Vibedasher Team
Product Team

Headless BI: Rent the Engine, Own the Frontend

There's a pattern that keeps winning in developer tools: split the thing you should own from the thing you should rent.

  • shadcn/ui gave you the component code. You own it, you edit it, it lives in your repo. No runtime dependency on a component vendor.
  • Supabase rented you the hard backend — Postgres, auth, storage, realtime — behind a clean SDK. You don't run the database; you call it.

Headless BI is that same split, applied to analytics: own your dashboard code, rent the data engine.

What "headless" means here

Classic embedded analytics gives you an iframe. The vendor hosts the chart, the vendor owns the rendering, and you get a rectangle on your page. It's fast to start and genuinely useful — but the dashboard is never yours. You can't restyle it past the theming knobs they expose, you can't fold it into your component library, and you can't diff it in a pull request.

Headless BI separates the two layers that were welded together:

LayerWho owns itWhy
Frontend — charts, layout, filters, interactionsYouIt's your product surface. It should be your code, your design system, your repo.
Engine — connectors, ETL, transforms, query, freshness, caching, row-level filteringUsIt's the hard, boring, expensive part. Renting it is the whole point.

You describe a dashboard, our AI builds it, and then you eject it: your AI pulls the dashboard's source via the Vibedasher MCP and rebuilds it natively in your app. The charts and layout become ordinary files in your repo. The only thing still wired to us is one call — client.query({ sql, params }) — that returns typed rows from the engine.

That's the shadcn move (you own the code) plus the Supabase move (you rent the hard backend), in one product.

Eject is a developer preview today, not generally available. The iframe door works in production right now. We're describing the model, and we'll ship the eject quickstart when it's flawless — not before.

Why owning the code beats owning a rectangle

The instinct is that an iframe is less lock-in than code threaded through your app — you can always delete a rectangle. That's exactly backwards for the thing you care about.

  • An iframe is a black box you rent forever. You never own the dashboard; you rent a view of it. Restyling, testing, and composing it are all limited to what the vendor's embed API allows.
  • Ejected code is yours. It reviews in a PR, restyles with your tokens, tests in your suite, and composes with the rest of your UI. If you outgrow a chart, you edit it — you're not filing a feature request.

The interesting inversion: owning the frontend code makes the engine stickier, not weaker. When your dashboards are real components in your repo, built around one SDK call, that call is threaded through your product. It's far harder to rip out than an iframe you can delete in one line — because you've built on it, not just embedded it. That's the shadcn effect. Lock-in that comes from usefulness, not from a hostage rectangle.

The part worth renting

Here's the honest pitch for renting the engine: the frontend is the fun part, and the engine is the part that quietly eats your quarter.

A production data layer is connectors that survive schema drift, incremental ETL that doesn't reprocess everything nightly, a query engine that joins across managed datasets, freshness tracking, a caching layer so repeat queries are instant, and row-level filtering so tenant A never sees tenant B's data. None of that is a weekend project, and none of it is your differentiator. It's undifferentiated heavy lifting — the textbook definition of what to rent.

So we run it, and we meter engine usage — queries and ETL — pay-as-you-go. You're not paying per "dashboard view" or per seat for a rectangle; you're paying for the compute the engine actually does. Cache hits are cheap. The frontend is free — it's your code.

The boundary is one method

The entire contract between your app and the engine is a single call:

const { columns, rows } = await client.query({
  sql,      // alias-only SQL (never a physical table name)
  params,   // { column: value } filters, bound server-side
});
// The engine infers the managed datasets from the aliases the SQL
// references — or pin an exact set with `datasetIds: [...]`.

The SQL names managed datasets by alias, never raw tables — so the engine can resolve each alias, apply row-level filters, and cache, all server-side (pass datasetIds explicitly when you want to pin the exact set; inference is a convenience, not an authorization relaxation). That's deliberate. It's what keeps this "the data layer your app is built around" rather than "a database connection string you could swap for any Postgres." Rent the pipeline, not just the storage.

Where this fits

  • Non-developers, existing site, minutes not hours → the iframe door. Zero-code, live today.
  • Developers who want the dashboard in their app, in their code → eject (preview). Own the frontend, rent the engine.

Two doors, one engine. Pick the one that matches how much of the frontend you want to own.

Next steps

Try the zero-code door today, and read where the eject model is headed at docs.vibedasher.com. Or spin up an account and describe your first dashboard.

Share this article