We are building our own analytics stack on camera, one layer a week. Supabase Postgres, Supabase Pipelines into BigQuery, models on top, and the numbers our own go-to-market people ask for on Mondays. This post is the written version of episode 1, The stack. Watch it on the episode page, it runs three minutes.
We started it for a boring reason. We could not answer basic questions about our own product, because our own collection layer had gaps. Most writing about this is either a vendor diagram or a tutorial that stops at the moment data lands in the warehouse, so we recorded ours as we went, including the parts we got wrong.
Key takeaways
- Four layers, and each one owns exactly one job. Mixing the jobs is how teams end up with a warehouse full of numbers nobody will defend in a meeting.
- Every downstream result depends on what upstream layers captured and delivered. BigQuery models what arrives; your CRM routes on what the model says.
- A wrong number can remain plausible through healthy downstream jobs. Replication health is not evidence that the source meaning was correct.
- That puts the real start of the stack one step before Postgres, at the pull request that changes the schema.
Four layers, four jobs
| Layer | Owns | Does not own |
|---|---|---|
| Supabase Postgres | The application records your product writes | Long-running warehouse analysis may compete with transactional work; assess it against your workload |
| Supabase Pipelines | Replicating eligible changes with at-least-once processing | Deciding whether rows are correct or preventing replayed changes |
| BigQuery | Modeling. Turning app tables into questions with answers | Knowing what your product meant by an active status |
| Your go-to-market tools | Acting on the answer | Any of the above |
The table is short on purpose. The second column is the one people write down, and the third column is the one that decides what your stack does under pressure. A layer that refuses a job is not a gap in the product. It is a boundary you have to staff yourself.
Postgres holds application records, while a warehouse is often a better fit for scans over long history. Supabase documents at-least-once processing, possible lag and errors, and recovery cases that require a new initial sync. Pipelines does not decide whether a row means what you think it means. See the Pipelines FAQ.
Every downstream result is conditional
Read the layers left to right and something uncomfortable falls out.
Pipelines moves supported changes, subject to documented delivery and recovery boundaries. BigQuery models what arrives. Your go-to-market tool routes on what the model says. Each layer stands on assumptions about the layer before it.
A wrong number at the far left can reach the far right while downstream jobs report healthy. Separately, replication can lag, replay a change, or require resynchronisation. Operational health and semantic correctness are different checks.
This is why the failures here look nothing like an outage. An outage tells you. A funnel that lost a step three weeks ago just looks like a slightly worse quarter.
PR that changes the schema
|
v
Supabase Postgres -> Pipelines (CDC) -> BigQuery -> GTM tools
| | | |
what happened replicates supported changes models it acts on it
The stack starts one step before Postgres
If the far-left box decides what everything downstream is allowed to be true about, then the stack does not start at Postgres. It starts at the pull request that changes the schema, or renames the event, or drops the write that nobody downstream knew was load bearing.
That is not a metaphor about culture. It is where the timestamps come from. A warehouse can model anything that arrived. It cannot conjure a moment nobody wrote down. Episode 5 is the one where this bit us directly: we defined time to value as the interval between installing our GitHub App and the first pull request review we post, and then found the install row had no usable timestamp. The pipeline was fine. The models were fine. The number was not computable, and no amount of warehouse work was going to fix it.
This is the one place our own product appears in the story. On an enabled repository, Skene may flag supported tracking changes from the pull request diff and policy. Reviews can be limited by filtered or truncated patches, so they are not proof that every branch or downstream dependency was checked. Fixing a missing write before merge avoids a gap that later warehouse work cannot recreate.
What we would tell you to decide first
Write down what each layer owns before you build any of it, in a paragraph a new engineer could read. Most stacks we have looked at do not have this written anywhere, and the argument that follows a bad number is really an argument about which layer was supposed to catch it.
Then decide the metric before you build the thing that computes it. We built the pipeline first and discovered the gap afterwards. The pipe was the easy part.
Watch the series
Episode 1, The stack is three minutes and shows the whole shape on one screen. Episode 2, Getting started with Pipelines is the first layer you can actually build: a publication, a destination, and a table sitting at Live. The written version of episode 2 is here.
Six more land weekly, through what to publish, modeling in BigQuery, activation, account health, expansion, and the migrations that break the chain. All of them, with the outline of each one before it ships, are at From Supabase Pipelines to GTM.
Continue with Skene
How Skene works
Skene reads the event writes in your code and checks them against your Supabase schema on every PR.
Skene vs. analytics tools
Compare keeping your telemetry in your own Supabase to shipping events to hosted product analytics platforms.
Pricing
Skene OSS is free and the free audit costs nothing. Pro is $249 a month; Enterprise is quoted.