Getting started

Project layout

One folder holds everything Yatta-related. Nothing is hidden from you, and nothing outside it is generated for you.

after yatta inittext
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.ts

main.ts

The entrypoint. bun run dev starts here. It boots the runtime, mounts each subsystem, and serves HTTP.

yatta/main.tsts
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.

conventiontext
backend/index.ts            →  /backend/user/index.ts       →  /userbackend/posts/[id].ts       →  /posts/:idbackend/users/[id]/posts.ts →  /users/:id/posts
Note
_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.

what to edit wheretext
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 infra

All 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

runtime datatext
Database/  app.db       ← schema + users + sessions  cache.db     ← L2 cache  jobs.db      ← queue, leases, dead letters storage/  uploads/     ← local disk driver
Note
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 schema in func/db.ts; it is created on the next boot
  • A job — add the name to AppJobs, register a handler in workers.ts
  • A subsystem — add the file, then register it in main.ts