Manifesto

The Postgres + Redis + cron stack is a bug, not an architecture.

Nobody designs it. Everybody ends up with it. This is why, and what should replace it.

You have built this.

You have a database. It holds the truth. Then the product needed to be fast, so the hot rows got copied into Redis. Then a dashboard needed a total, so a cron job started recomputing it every five minutes. Then a rule had to run when an order changed, so it moved into a worker behind a queue. Then something had to know which cache key to delete when the row changed, so you wrote that too. And all of it connects to the database as one account, with one password, so the code in front decides on behalf of every user what they may see.

None of these were mistakes. Each one was the reasonable next step. Look at the whole thing and it is five systems holding one application's state, held together by code whose only job is keeping them from disagreeing. When they do disagree, and they do, the database says one thing, the cache says another, the dashboard says a third, and all three carry a fresh timestamp.

You did not architect that. You accumulated it.

Today+---------------+
|   POSTGRES    |
+---------------+
    ~ glue ~
+---------------+
|     REDIS     |
+---------------+
    ~ glue ~
+---------------+
|     CRON      |
+---------------+
    ~ glue ~
+---------------+
|     QUEUE     |
+---------------+
    ~ glue ~
+---------------+
|    WORKERS    |
+---------------+

five systems, one state

        |
        v

With ReifyDB+---------------+
|    REIFYDB    |
|               |
|  tables       |
|  views        |
|  transitions  |
|  primitives   |
+---------------+

one system, one transaction

Every box is an apology.

Each system in that stack exists because the database could not do one specific thing. Read them as what they are: workarounds, each with a cost you pay every day.

[ REDIS ]The hot copy.

The database could not serve these rows fast enough, so now there are two of them. One is right.

[ CRON ]The refresh.

The database could not keep a derived number current, so it is recomputed on a timer. Between runs it is wrong, and it looks fresh.

[ QUEUE + WORKERS ]The rule, later.

The database could not run your logic when the data changed, so the logic runs afterwards, elsewhere, and hopes the data has not moved.

[ SERVICE ACCOUNT ]The one password.

The database could not tell your users apart, so everything connects as one privileged account and the code in front of it decides who may do what. Every rule lives twice, one connection can do anything, and queries get built from user input on the way through.

[ GLUE ]The code that knows.

None of the above knows about the others, so you wrote the code that does. It is the most fragile code you own, and it ships no feature.

How it got this way.

Databases were built to be systems of record. Write it down, get it back, keep it safe. That was the job, and they are very good at it.

But the state an application reasons about on every request is not a record. It is a balance that moves with every trade. A player position that changes every tick. A workflow that is in exactly one step. A rate limit that is either exceeded or not. It is live, it is derived, and it is bound by rules. Nothing in the record model holds that, so it was pushed out of the database, one piece at a time, into the stack above.

Databases became systems of record. Applications need systems of live state.

What ReifyDB is built on.

01

Derived state is the database's job.

If a number can be computed from your data, you should never maintain it by hand. Not with a cron job, not with a cache key, not with a worker that hopes it ran in time. The write that changes the data is the thing that updates the number.

02

A rule enforced in a service is a rule enforced sometimes.

Say a balance may never go below zero. If that check lives in a service, it holds only for writes that go through that service. The migration script, the support tool, the worker someone adds next quarter: none of them know the rule exists. Put the check on the data, inside the write that changes it, and there is no way around it.

03

One write, one truth.

If a change and its consequences cannot commit together, you do not have a system. You have two systems and a race between them. Rollback has to mean everything rolls back.

04

Counters, queues, and buffers are state, not cache.

They deserve the same transaction as the row next to them. Rebuilding them in a second store is how a balance and a rate limit end up disagreeing about the same second.

05

The network is the speed limit.

Every round trip between your data and your logic is latency you paid for and correctness you gave up while waiting. The hot path should not have a network in it.

06

The application user is the database user.

Every client authenticates to the database as itself, and policies decide, per user, what may be read and written. There is no shared service account and no privileged connection to hijack: a hostile query runs as the user, with the user's permissions, and can do nothing the user could not do anyway. Nothing to inject into, and no second copy of the rules in an API layer to drift.

What ReifyDB is.

ReifyDB is one database for that state. Tables hold the rows. Views hold the derived numbers, and the write keeps them current; there is nothing to refresh. Rules are procedures and handlers: code you version and test inside the database, running inside the transaction that changes the data. Not a trigger someone forgot. Counters, queues, ring buffers, and histograms are built in, transactional, and one query away. Embed it in your process or run it as a server. Either way, the hot path has no network in it.

It also knows who is asking. Clients authenticate to the database as themselves, over WebSocket or HTTP, and policies gate every read and write per user. There is nothing in front of it holding the one password or re-checking permissions: clients talk to ReifyDB, and the rules about who may do what live with the data, like every other rule.

Same feature, two stacks. Alice places an order. First on today's stack, then on ReifyDB.

Today
alicePOST /orders
api servermay alice? build the query
as "app", the one account
postgresinsert, debit
  • redisdrop cached balance
  • queueworker: totals
  • cronrevenue, later
alicepolls balance, revenue: stale in between
5 systemsruns as "app"stale
With ReifyDB
aliceplace_order(...)
reifydb
policy
alice may place orders
procedure
check balance, insert, debit
view
revenue, updated by the same write
one transaction
alicesees balance, revenue: current, pushed
1 systemruns as alicecurrent
Status

Version 0.9. Not production ready.

APIs and guarantees will change, and every page says so. What will not change is the list above.

If you have written that cron job. If you have shipped a service whose entire job is knowing which key to delete. If you have ever explained to someone why the dashboard and the database disagree. Then you already agree with this page.

Agree, and come build it. Disagree, and say so.

One database instead of Postgres + Redis + a queue + a cron job.