Insights
What we ran into along the way.
No tips and tricks. Notes from building real products, with the numbers and the miscalculations included.
-
could not serialize access due to concurrent update
PostgreSQL error 40001 'could not serialize access due to concurrent update', measured on 17: when it fires, why SKIP LOCKED does not avoid it, and the retry.
Read on · 7 min read -
CREATE POLICY IF NOT EXISTS in PostgreSQL: what works
PostgreSQL has no CREATE POLICY IF NOT EXISTS. Three ways to write a repeatable policy migration, measured on PostgreSQL 17 and 18: gaps, locks and races.
Read on · 7 min read -
idle in transaction in PostgreSQL: what it holds
A PostgreSQL session idle in transaction, measured on 17: what it blocks (locks, ALTER TABLE, vacuum) and how idle_in_transaction_session_timeout ends it.
Read on · 7 min read -
invalid input syntax for type uuid in PostgreSQL, measured
What raised 'invalid input syntax for type uuid' in PostgreSQL 17, measured: which strings cast, 'undefined' from a driver, '' from a setting, and fixes.
Read on · 7 min read -
remaining connection slots are reserved in PostgreSQL
'remaining connection slots are reserved for roles with the SUPERUSER attribute': why PostgreSQL refuses you, measured on 15–17, and how to free slots.
Read on · 6 min read -
stack depth limit exceeded in PostgreSQL: four causes
What raised 'stack depth limit exceeded' in PostgreSQL 17, measured: triggers, recursion, a policy reading its table via a function, long expressions.
Read on · 7 min read -
unrecognized configuration parameter in PostgreSQL
Restoring a pg_dump 17 file into PostgreSQL 16 fails with unrecognized configuration parameter transaction_timeout. Measured fixes, plus four other causes.
Read on · 7 min read -
Rails, ActiveRecord and PostgreSQL RLS, measured
Setting the tenant for PostgreSQL row-level security in Rails 8.1, measured: before_action, a transaction per request, threads in a request, failed writes.
Read on · 7 min read -
Hibernate multi-tenancy and PostgreSQL RLS in Spring Boot
Where to set the tenant for PostgreSQL row-level security in Spring Boot 4 and Hibernate 7, measured: DataSource wrapper, interceptor, @Transactional, provider.
Read on · 8 min read -
TypeORM and PostgreSQL row-level security, measured
Setting the tenant for PostgreSQL row-level security in TypeORM 1.1, measured: dataSource.query, QueryRunner, transactions, and an injected repository.
Read on · 7 min read -
Go, pgx and PostgreSQL row-level security, measured
Setting the tenant for PostgreSQL row-level security in Go with pgx 5.11, measured: pgxpool, PrepareConn hooks, transactions, batches and PgBouncer.
Read on · 10 min read -
ALTER DEFAULT PRIVILEGES not working? What we measured
ALTER DEFAULT PRIVILEGES in PostgreSQL 17, measured: whose new tables it covers, why a per-schema revoke does nothing, what counts as a table, how to list it.
Read on · 9 min read -
Who bypasses row-level security in PostgreSQL? Measured
BYPASSRLS, table owners, FORCE and superusers in PostgreSQL 17, measured: who sees every row, what role membership passes on, and what RLS never covers.
Read on · 7 min read -
current_setting and set_config in PostgreSQL, measured
What current_setting and set_config do with a custom setting in PostgreSQL 17, measured: NULL or empty string, how long a value lasts, defaults, who may set it.
Read on · 10 min read -
must be owner of table in PostgreSQL: who may alter it?
What raised 'must be owner of table' in PostgreSQL 17, measured: which statements need ownership, which a grant covers, and how tables end up with mixed owners.
Read on · 8 min read -
permission denied for table in PostgreSQL: which grant?
What raised 'permission denied for table', schema and sequence in PostgreSQL 17, measured: the privilege each statement needs, and why default privileges miss.
Read on · 10 min read -
A read-only user in PostgreSQL: what it can still do
Three ways to create a read-only user in PostgreSQL 17, measured: what each still allows, from a write through a function to password verifiers and RLS.
Read on · 9 min read -
PostgreSQL row-level security for SaaS: what we measured
Row-level security for a multi-tenant SaaS on PostgreSQL 17, result by result: what leaks, what it costs, how to set the tenant, and where each test is.
Read on · 7 min read -
infinite recursion detected in policy: causes and fixes
When PostgreSQL 17 raises 'infinite recursion detected in policy for relation', and what each fix costs on a million rows: from 0.09 ms to 6.6 seconds.
Read on · 9 min read -
new row violates row-level security policy: the causes
What raised 'new row violates row-level security policy for table' in PostgreSQL 17, measured: inserts, RETURNING, upserts, MERGE and four message forms.
Read on · 9 min read -
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
Row-level security not working in PostgreSQL: why a query returns no rows, or all of them. Five checks and two catalog queries, 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 · 9 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 · 16 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.