---
title: "Tech Stack"
description: "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."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.taverncozy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tech Stack

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

- **Card** — **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.
- **Card** — **Web — TanStack Start.** Full-stack React on Vite. TanStack Router drives routing, TanStack Query drives data, SSR is served by Nitro (bun preset).
- **Card** — **Chat — TanStack AI.** AI chat via `@tanstack/ai` with the OpenRouter adapter. Messages stream as SSE straight to the browser.
- **Card** — **API — Elysia 2.** A Bun-native web framework. Type-safe routes, middleware, and guards on the `/api` surface.
- **Card** — **Auth — Better Auth.** Email/password, Google OAuth, passkeys, multi-session account switching, admin roles, and Turnstile captcha — all server-side.
- **Card** — **Data — Drizzle ORM on SQLite.** `bun:sqlite` reads and writes one file. Drizzle gives typed queries, migrations, and a schema.
- **Card** — **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.

> **Note**
>
> "No latency" refers to the *internal* path — app → API → SQLite. Internet latency to the user still exists, of course; Cloudflare at the edge handles TLS and caching.

## 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.

Source: https://docs.taverncozy.com/tech-stack/index.mdx
