Insights
What we ran into along the way.
No tips and tricks. Notes from building real products, with the numbers and the miscalculations included.
-
Django and PostgreSQL row-level security, measured
Setting the tenant for PostgreSQL row-level security in Django 5.2, measured: persistent connections, the 5.1 pool, ATOMIC_REQUESTS and middleware.
Read on · 7 min read -
Drizzle and PostgreSQL row-level security, measured
PostgreSQL row-level security with Drizzle ORM 0.45, measured: setting the tenant per request, the documented wrapper, and what drizzle-kit leaves out.
Read on · 6 min read -
Laravel and PostgreSQL row-level security, measured
Setting the tenant for PostgreSQL row-level security in Laravel 13, measured: middleware, persistent PDO connections and DB::transaction around a request.
Read on · 6 min read -
Debugging row-level security in PostgreSQL
Why does a query under row-level security return no rows, or all of them? Five checks and two catalog queries, tested in PostgreSQL 17, with the output.
Read on · 7 min read -
PostgreSQL job workers: retries, crashes, tenant context
One worker serving every tenant, measured in PostgreSQL 17 with psycopg: which tenant context outlives the job, why failures go uncounted, what a crash leaves.
Read on · 11 min read -
One partition per tenant in PostgreSQL, measured
List-partitioning by tenant under row-level security, measured in PostgreSQL 17 and 18: 100, 1,000 and 3,000 partitions, planning, locks, adding a tenant.
Read on · 9 min read -
RLS in PostgreSQL: USING vs WITH CHECK on writes
Which writes fail, which silently do nothing and which cross tenants under row-level security, measured in PostgreSQL 17 for six policy setups.
Read on · 7 min read -
PostgreSQL views and row-level security, measured
Which views leak other tenants' rows under row-level security, measured in PostgreSQL 17: view owner, BYPASSRLS, security_invoker, materialized views.
Read on · 6 min read -
Prisma and PostgreSQL row-level security, measured
Setting the tenant for PostgreSQL row-level security in Prisma 7, measured: $executeRaw, batch and interactive transactions, and the client extension.
Read on · 8 min read -
SQLAlchemy and PostgreSQL row-level security, measured
Setting the tenant for PostgreSQL row-level security in SQLAlchemy 2.1, measured: the connection pool, set_config, after_begin and the reset hook.
Read on · 9 min read -
Exporting one tenant with pg_dump and row-level security
pg_dump has no WHERE clause, but row-level security can be one. Tested on PostgreSQL 17: one tenant's rows, the sequence values that leak, restoring under RLS.
Read on · 6 min read -
PgBouncer and RLS: tenant context, SET LOCAL, shared plans
RLS behind PgBouncer in transaction mode, measured: which tenant context leaks, what SET LOCAL does outside a transaction, and one plan shared by tenants.
Read on · 9 min read -
Audit log per tenant in PostgreSQL: what a trigger costs
A trigger-based audit log in PostgreSQL 17, measured: row against statement triggers, full rows against changed columns, and row-level security on the log.
Read on · 7 min read -
Counting per tenant in PostgreSQL: count, estimate, counter
count(*) per tenant in PostgreSQL 17, measured: why it got 5× slower for the largest tenant, when estimates are wrong, and what a counter row costs under load.
Read on · 7 min read -
Deleting one tenant in PostgreSQL: cascade, batch or DROP
Deleting one tenant from a shared PostgreSQL 17 database, measured: cascade, batches or dropping a partition; locks, batch size, disk space, what stays behind.
Read on · 7 min read -
Job queues per tenant in PostgreSQL: the noisy neighbour
One tenant queues 1,000 jobs, ten others five each: FIFO against round-robin with SKIP LOCKED in PostgreSQL 17, measured, plus a 10-second planner trap.
Read on · 8 min read -
Moving one tenant with logical replication row filters
Moving one tenant to its own PostgreSQL 17 database with a row-filtered publication, measured: the replica identity trap, WAL cost, cut-over, sequences.
Read on · 7 min read -
A role per tenant vs a session variable for PostgreSQL RLS
Row-level security in PostgreSQL 17 with a role per tenant or a session variable, measured: SET ROLE at 10,000 roles, PgBouncer, injection, definer functions.
Read on · 7 min read -
Schema migrations on a shared multi-tenant PostgreSQL table
ALTER TABLE on a table every tenant shares, measured on PostgreSQL 17: the lock queue, lock_timeout, rewrites, NOT VALID, and changing tenant_id under RLS.
Read on · 7 min read -
Unique per tenant in PostgreSQL: soft delete and RLS leaks
Unique constraints in multi-tenant PostgreSQL 17, tested: per tenant or global, soft delete, case, NULLs, ON CONFLICT, and what a duplicate-key error reveals.
Read on · 6 min read -
Row-level security performance in PostgreSQL, measured
What an RLS policy costs in PostgreSQL 17: function volatility, the (select …) wrapper, membership subqueries and the leakproof rule that disables your index.
Read on · 9 min read -
Invoice numbers per tenant in PostgreSQL, without gaps
Sequence, max()+1, SERIALIZABLE or a counter row: five ways to number invoices per tenant, measured under load in PostgreSQL 17 for duplicates, gaps and speed.
Read on · 9 min read -
PostgreSQL indexes for multi-tenant SaaS: tenant_id first
Five indexes, 1,000 tenants, one query, measured in PostgreSQL 17: why tenant_id goes first, what RLS does to the plan, and when partitioning pays off.
Read on · 9 min read -
An MCP server for an existing SaaS: 17 tools in production
What we learned from an MCP server on Pilot-Next: 14 read and 3 write tools, an 11 KB tool list, a preview before every write, and the date models get wrong.
Read on · 10 min read -
Multi-tenant SaaS on PostgreSQL: six decisions
The six choices a multi-tenant SaaS locks into PostgreSQL: isolation model, RLS, indexes, money, restoring one tenant and migrating at scale. All measured.
Read on · 12 min read -
Row-level security in PostgreSQL: where tenants leak
Turning RLS on takes five lines of SQL. These are the five ways it is silently off afterwards, or leaks around the edges — each one measured in PostgreSQL 17.
Read on · 10 min read -
Money in PostgreSQL: numeric, integer cents or money?
Which PostgreSQL type holds money exactly? numeric, integer cents, bigint and money side by side, with the pitfalls we tested and a query to audit your schema.
Read on · 8 min read -
Multi-tenant architecture: choosing an isolation model
Database per customer, schema per customer or one database with tenant_id and row-level security: the models side by side, and the three questions that decide.
Read on · 11 min read -
Three decisions in a SaaS product you never get to undo
Customer separation, money and permissions. What each of the three costs up front, what it costs afterwards, and how to check your own product in ten minutes.
Read on · 6 min read -
Building software with AI: seven questions to ask
What to ask a firm that builds with AI agents: who owns the code, who is liable, how it gets tested, and whether anyone else can take it over later.
Read on · 8 min read -
Money in a SaaS product: cents, not floats
The second irreversible decision in a SaaS product is about money. Why a floating-point number loses your cents, and where it still goes wrong with cents.
Read on · 8 min read -
Permissions in SaaS: roles, not checkboxes
The third irreversible decision: who may do what. Why a list of checkboxes per user seizes up after twenty customers, and what does work instead.
Read on · 8 min read -
A nightly crew of AI agents: maintenance while you sleep
Every night a crew of agents removes dead code, fills test gaps and measures search visibility. How it is set up, and why it is only safe behind gates.
Read on · 8 min read -
Multi-tenant from day one, or it never gets fixed
Three decisions in a SaaS product are nearly impossible to reverse. Separating customers is the first, and the most expensive one to skip.
Read on · 7 min read -
What building a SaaS product with AI agents really costs
Two products, built solo with AI coding agents. What went faster than expected, what was more expensive, and the mistake that slipped through three times.
Read on · 7 min read
Let's talk
What are we building?
One conversation is enough to know whether we fit. Tell us what you have in mind — we will tell you how fast it can happen, and whether we are the right people for it.