The Cruto backend is a small surface area. FastAPI, Postgres, a single background worker, Stripe, Clerk, Gemini, Judge0. That's the stack. We try to add nothing else.
The biggest single decision: Postgres for everything we can stretch it to.
Things Postgres does for us that another tool would normally do
- Queues —
SELECT FOR UPDATE SKIP LOCKEDwith a worker poll. We don't run Redis or RabbitMQ. - Full-text search —
tsvectoron the posting text. Good enough until we hit 10x the corpus. - Rate limiting — token-bucket counters in a small table. The auth layer reads/writes once per request.
- Idempotency keys — a unique constraint on
(user_id, key). Inserting twice is a no-op. - Audit log — append-only table. We use it for billing reconciliation and abuse detection.
Where we did add another tool
Three places. Embedding storage went into pgvector because the alternative was a separate service (we still got to keep it inside Postgres). Sandboxed code execution is Judge0 because we are not in the business of building syscall-isolated process pools. Live audio is Gemini Live because we are not in the business of building real-time voice models.
Everything else is Postgres. The benefit isn't novelty; it's that the on-call surface is one process, the deploy story is one migration, and a new engineer can read the schema and understand the entire backend in an afternoon.