Skip to content

Tech Stack

The stack behind Tavern Cozy — TanStack Start, TanStack AI, Elysia 2, Drizzle on a single local SQLite file, built as a monolith for zero-latency development.

Updated View as Markdown

Tavern Cozy is deliberately built as a monolith with a local database. The web app, the API, and the database all live on the same machine — the web app proxies /api to the API process, and the API reads and writes one local SQLite file. There are no microservices, no remote database, no cross-network hops in the request path.

That design is what keeps it fast: every request stays on the box. This page documents the stack for the record.

The stack at a glance

Runtime — Bun. Both the API and the web app run on Bun, in dev and in production. One runtime, no build-tool friction, and native-speed SQLite bindings.

Web — TanStack Start. Full-stack React on Vite. TanStack Router drives routing, TanStack Query drives data, SSR is served by Nitro (bun preset).

Chat — TanStack AI. AI chat via @tanstack/ai with the OpenRouter adapter. Messages stream as SSE straight to the browser.

API — Elysia 2. A Bun-native web framework. Type-safe routes, middleware, and guards on the /api surface.

Auth — Better Auth. Email/password, Google OAuth, passkeys, multi-session account switching, admin roles, and Turnstile captcha — all server-side.

Data — Drizzle ORM on SQLite. bun:sqlite reads and writes one file. Drizzle gives typed queries, migrations, and a schema.

Sounds — cuelume. Interaction sounds synthesized live in the browser via Web Audio (17-sound palette, zero audio files). A per-user toggle persists to the profiles table; buttons, nav, modals, toggles, and chat events each map to a context-appropriate sound.

Why a monolith with local SQLite

  • Zero latency by construction. The API and the database are on the same host; a query is a local file read, not a network call. No DB connection pool to tune, no remote round-trip to hide.
  • One deploy, one box. Web + API + SQLite ship together. Deploys are a git pull and a process restart.
  • Simple to reason about. No distributed-system failure modes: if the process is up, the data is there.
  • Fast to develop. The whole stack boots from a single bun command — no orchestrator, no containers, no service wiring.

How the pieces talk

Browser
  │  HTTPS (Cloudflare edge)

nginx ──► tavern-start (TanStack Start, Nitro, :3000)
             │  proxies /api/**  (plus OAuth redirect passthrough)

          tavern-elysia (Elysia 2, Better Auth, :3001)
             │  reads/writes one local file

          data/tavern.db (SQLite, WAL mode)

Chat streams are SSE: tavern-elysia streams tokens through the /api proxy to the browser, with no intermediate service.

The details

Runtime & language

  • Bun — the single runtime for both servers and the build tooling. Bun canary is used in dev, matching the dependency policy below.
  • TypeScript everywhere — web app, API, schema, and tests.
  • Dependency policy — always the latest release of every library, including beta/canary dist-tags (e.g. Bun canary, Elysia’s experimental tag, TanStack 1.x canary line). No pinning to stable-only; patches land as they publish.

Web app (tavern-start)

  • TanStack Start — full-stack React framework (Vite-based, Nitro SSR with the bun preset).
  • TanStack Router — typed file-based routing.
  • TanStack Query — server state, caching, and invalidation.
  • Tailwind CSS — styling, with shadcn-style UI primitives built on Base UI.
  • cuelume — interaction sounds (Web Audio, no audio files); per-user enable/disable saved to profiles.soundsEnabled and applied app-wide at the root shell.
  • Paraglide (inlang) — i18n (English + Spanish).
  • Expo / React Native — the mobile app, built with EAS, Google sign-in, RevenueCat subscriptions.

API (tavern-elysia)

  • Elysia 2 — Bun-native HTTP framework with typed context and plugins.
  • Drizzle ORM — typed SQL queries against SQLite.
  • Better Auth — the full auth surface: email/password + username, Google OAuth, passkeys, multi-session, admin roles, Turnstile captcha.
  • OpenRouter — LLM + image-model access via @tanstack/ai adapters.
  • R2 — object storage for uploaded images (the one cloud dependency, used only for media).

Database

  • SQLite via bun:sqlite, a single file (data/tavern.db) in WAL mode with foreign keys on and a busy timeout.
  • Drizzle manages the schema, and the boot path auto-reconciles missing columns so old databases upgrade in place.

Repository layout

tavern-workspace/
├── tavern-start/   # TanStack Start web app (Vite + Nitro)
├── tavern-elysia/  # Elysia 2 API (Bun) + SQLite
├── tavern-expo/    # Expo / React Native mobile app
└── tavern-docs/    # this documentation site (Astro)

For running each service, see the AGENT.md in each package — that’s the source of truth for commands.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close