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, which 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 guarantee is conditional on the layer to its left. Pipelines guarantees delivery, not truth. BigQuery models whatever arrives. Your CRM routes on whatever the model says.
- A wrong number entering on the left arrives on the right on time, intact, and green at every hop, because stopping it is not any of these layers' job.
- 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 record of what happened in the product | Analysis. It is a transactional database and you should not run funnels on it |
| Supabase Pipelines | Moving those rows, faithfully, with no silent loss | Deciding whether the rows are correct |
| 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 is the clearest case. It holds the truth about what happened, and it is the worst place in the stack to ask a question that scans months of history. Pipelines is the next clearest. It is built to survive infrastructure failure and to move every change without dropping any, and it is not built to have an opinion about whether a row means what you think it means.
Every guarantee is conditional
Read the layers left to right and something uncomfortable falls out.
Pipelines guarantees delivery, not truth. BigQuery models whatever arrives. Your go-to-market tool routes on whatever the model says. Each layer is doing its job correctly, and each one is standing on an assumption about the layer before it.
So a wrong number at the far left arrives at the far right on time, intact, and green at every hop. The pipeline dashboard is healthy. The scheduled query runs. The score lands in the CRM. Nothing in the chain is designed to stop it, because stopping it is not any of these layers' job.
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 moves it faithfully 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, and it is one specific thing rather than a layer of the stack. Skene reviews every pull request on a linked repository and requests changes when a change breaks what your tracking records, with the comment on the line that did it. The fix has to happen before merge, because after merge the code is still fixable and the three weeks of missing data are not.
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.
Episode 1 is three minutes and shows the whole shape on one screen. Episode 2 is the first layer you can actually build: a publication, a destination, and a table sitting at Live.
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.
