Getting started
Project layout
One folder holds everything Yatta-related. Nothing is hidden from you, and nothing outside it is generated for you.
my-api/├── package.json├── tsconfig.json│└── yatta/ ├── main.ts ├── backend/ │ ├── _router.ts │ └── index.ts └── func/ ├── db.ts ├── auth.ts ├── cache.ts ├── mail.ts ├── storage.ts ├── jobs.ts ├── events.ts ├── cron.ts ├── workers.ts ├── realtime.ts └── routerHelper.tsmain.ts
The entrypoint. bun run dev starts here. It boots the runtime, mounts each subsystem, and serves HTTP.
const runtime = createRuntime({ taskTimeoutMs: 30_000 });await runtime.start(); const subsystems = [ defineSubsystem({ name: "auth", entrypoint: ..., workload: "cpu" }), defineSubsystem({ name: "jobs", entrypoint: ..., workload: "cpu" }), defineSubsystem({ name: "db", entrypoint: ..., workload: "io" }), // …]; for (const subsystem of subsystems) { await runtime.registerSubsystem(subsystem);} const server = Bun.serve({ port, fetch, websocket: realtime.websocket });backend/ — your routes
This is where most of your code goes. Files map to paths; anything without a matching file is a 404.
backend/index.ts → /backend/user/index.ts → /userbackend/posts/[id].ts → /posts/:idbackend/users/[id]/posts.ts → /users/:id/postsNote
_router.ts is infrastructure — you can leave it alone. It handles matching, trailing-slash fallback, security headers and the/storage and /realtime routes.func/ — one file per engine
Each file configures one engine. These are meant to be edited: the schema, the disk list, the job names, the mail templates.
func/db.ts schema — your tablesfunc/auth.ts auth config + the SQLite auth storefunc/cache.ts cache sizing and TTLfunc/mail.ts templates and layoutsfunc/storage.ts disks: local, s3func/jobs.ts job names (AppJobs)func/events.ts event names (AppEvents)func/cron.ts schedulesfunc/workers.ts job handlersfunc/realtime.ts WebSocket/SSE handlersfunc/routerHelper.ts routing infraAll of them are mounted as subsystems, so each runs on its own worker thread. auth.ts and jobs.ts sit on the CPU pool; the rest are I/O.
Where things are stored
Database/ app.db ← schema + users + sessions cache.db ← L2 cache jobs.db ← queue, leases, dead letters storage/ uploads/ ← local disk driverNote
Both directories are created on first boot and are disposable. In production, mount them as volumes — or point storage at S3 and keep only the database.
Adding things
- A route — drop a file into
backend/, then restart (new files need a restart; edits hot-reload) - A table — add it to the
schemainfunc/db.ts; it is created on the next boot - A job — add the name to
AppJobs, register a handler inworkers.ts - A subsystem — add the file, then register it in
main.ts