347 private links
In this post, I’ll walk through a set of common misconceptions that drive teams to introduce new infrastructure when they don’t need to. All of these can be solved with vanilla PostgreSQL 18 using standard extensions available on RDS, with no special infrastructure and no distributed-systems cosplay.
The database can be used for many things people often miss:
- user roles (finance) for modularity. In particular, a proper role can be used for defining very precise interfaces on top of database objects
- domains can be defined as an application of the abtract data type to database management
- a table for transfers can be stored with a system-time temporal table
- account audits (store old versions for logs)
- transaction state machine with functions
- record size estimation
- Heap-Only Tuple to avoid write amplification when primary keys are aligned with immutable columns. It enables faster updates. See https://ebellani.github.io/blog/2026/all-you-need-is-postgresql/#introduction:~:text=Enabling%20HOT%20Updates%20for%20Transfers,-By
- excellent OLTP (quick read and write individual rows) with a primary key reflecting the access pattern
- view to reuse queries from multiple tables
- excellent OLAP: large volumes of data while allowing quick query response times: a
finance.balance_ledgertable stores a snapshot of both balances after every transaction. - incremental maintenance via triggers
- correct isolation with
alter role finance set default_transaction_isolation = 'serializable';. If a cyclic transaction is detected, then one of the transaction fails. The application must be prepared to retry aborted transactions, but the invariants are never violated.
Key takeaways:
- 766 TPS overall with 0 failed transactions. The startup target of 10,000 transfers/day is ~0.12 TPS. We exceed that by over 6,000x, confirming massive headroom on modest hardware.
- 0 serialization failures: Despite 10 concurrent clients writing to 100 accounts under SERIALIZABLE isolation, no transactions were aborted. The working set is distributed across enough accounts that write contention is negligible at this scale.
- 8ms average read latency: The UNION ALL view over 4 tables plus the balance ledger lookup completes well within interactive response time, even as the tables grow throughout the 60-second run.
- 33ms average write latency: Each write transaction exercises the full constraint set that implements complex business logic (audit trails, time constraints, balances, etc) all within 33ms. This is the true cost of enforcing every business rule at the data level, and it is more than acceptable.
The full SQL is provided at the end.
wrappers, pgrx, pgdog, ParadeDB, Neon (Postgres in S3)
Indeed Rust is efficient. Postgres also covers a lot of features.
I didn't read it but look after the strategies: sequences with serial IDs, for update skip locked
So, it's a matter of your requirements. If you need massive scale and throughput (> 100k messages/sec), Kafka will be hard to beat. But if you're not operating at that scale, Postgres is hard to beat.
So, it's a matter of your requirements. If you need massive scale and throughput (> 100k messages/sec), Kafka will be hard to beat. But if you're not operating at that scale, Postgres is hard to beat.
Fewer moving parts means you move faster. More importantly, you can make architectural changes faster. When your infrastructure is basically “one Postgres instance,” new developers can get the full stack running on their laptop in minutes, not days.
JSONB columns for schemaless key-value store.
Job queues with a SQL table running SELECT ... FOR UPDATE SKIP LOCKED
Full-text search built-in
Yes, you should use the best tool for each job, but every tool is another thing that can break, to deploy, to hires need to learn and to keep up.
When to not use Postgres: the queries starts taking 100s milliseconds and the indexing is exhausted. Once this happen, you'll have a clear spec
Here's the thing: 99% of companies don't need them. The top 1% have tens of millions of users and a large engineering team to match.
The fun thing about Postgres is there is already an extension for that: PostGIS, Full-text search, JSONB, TimescaleDB, pgvectorm, and many for AI
Each database add hidden costs: backup strategy, monitoring dashboards, seceurity patches, on-call runbooks, failover testing.
SLA math: Three systems at 99.9% uptime each = 99.7% combined
Why? Costs, operational complexity, data consistency
- Caching with UNLOGGED table (that I've also found in other posts)
- Pub/Sub with LISTEN/NOTIFY
- Job Queues with SKIP LOCKED
- Rate Limiting is also possible
- Sessions with JSONB
PostgresSQL ist nearly 2 times slower compared to Redis, but is it worth it?
When to keep Redis?
- extreme performance needed
- using redis-specific data structures
Migration strategy:
- Side by side
- Read from Postgres
- Write to Postgres only
- Remove Redis
and Prisma provide for example typedSQL to have a smooth integration with Typescript.
It may be useful later:
- storing response variables
- transposing data
- showing SQL statements and output in the same file
A script
Hacker news thread: https://news.ycombinator.com/item?id=46092338
PostgresSQL if the service needs close to 99.999% availability, or more than 1 Gpbs of bandwidth or if the database is expected to grow larger than 100-200GB.
256GB means the SQLite DB can fit in RAM, or the migration will be too slow for the sqlite file and block the service.
It's important to note that with the advent of DuckDB, Parquet and Apache Iceberg, tehre are less and less reasons to stuff your main DB with timeseries data and instead only keep some kind of materialized view and send the raw data to S3.
For everything else, SQLite.
After a few years of using both (see Optimizing SQLite for servers for example), I've found that SQLite particularly shines when used for internal services or public services where a small amount of downtime is tolerable.
So, I choose PostgreSQL (preferably with a managed provider) if the service needs (close to) 100% uptime, if the service needs more than 5 Gbps of bandwidth or if the database is expected to grow larger than 200GB. [...] Bascially, all the situations where running on a single server is not possible.
It's important to note that with the advent of DuckDB, Parquet and Apache Iceberg, there is less and less reasons to stuff your main database with
useless junktimeseries data, and instead only keep some kind of materialized view and send the raw data to S3. Thus, there are less and less reasons for your main database to be over 200 GB.
Redis is faster, but they have the same order of magnitude. Maybe +1 order for Postgres in same examples.
The comparison of a lot of data does not made though.