cruto.ai
← All posts
Engineering · 7 min read

Boring Postgres, everywhere: how Cruto's backend stays small

We use Postgres for everything we can. Queues, full-text search, rate limits, even some embedding storage. Notes from a small team that wants to ship.

The Cruto team · January 8, 2026

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

  • QueuesSELECT FOR UPDATE SKIP LOCKED with a worker poll. We don't run Redis or RabbitMQ.
  • Full-text searchtsvector on 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.

Try Cruto

The interview-prep platform that knows your pipeline.

Free tier includes 5 imports + 3 tests + 15 min of live interview every month. No credit card.

Sign up free
More posts