Elysia + TanStack Dashboard - Blueprint
Authenticated dashboard starter with Elysia, TanStack Start, and PostgreSQL, typed end to end
An opinionated starter for authenticated web products, built with Elysia on Bun and TanStack Start, managed as a Turborepo monorepo. One repository, two services, one database.
Tech stack:
| Layer | Technology |
|---|---|
| API | Elysia on Bun, port 3001 |
| Type safety | Eden - the web app imports the API type, no codegen, no shared DTO package |
| Auth | better-auth cookie sessions, email and password, OIDC-ready |
| Database | PostgreSQL + Drizzle ORM |
| Web | TanStack Start + TanStack Query + shadcn/ui on Base UI, port 3000 |
What You Get
- A private clone of the monorepo in your GitHub account, one repo for both services
- Two Rock8Cloud services: the Elysia API and the TanStack Start web app
- A managed PostgreSQL database, pre-wired via
DATABASE_URL - A generated auth secret and a seeded demo account
- A working todo vertical slice showing the route to service to query layering
The services learn each other's URLs automatically. The API knows its own public URL (BETTER_AUTH_URL) and the web origin (CORS_ORIGIN), and the web app is built against the API public URL. No manual URL setup.
Your Demo Login
The API is seeded with demo@example.com and a password generated for your deployment. Read it from SEED_USER_PASSWORD in the API service's environment variables, then sign in at /login on the web URL.
Change the password or delete the account once you have your own user. Set SEED_DEFAULT_USER=false to stop seeding entirely.
Sign-up is open by default. Anyone who reaches your web URL can register an account. Restrict or disable emailAndPassword in apps/server/src/lib/auth.ts before putting anything real behind it.
Changing the API URL
VITE_SERVER_URL is inlined by Vite at build time, so it is passed as a Docker build argument rather than a runtime variable. If you move the API to a different URL, the web service needs a rebuild, not just a restart.
Database Migrations
Migrations run automatically when the API starts. To change the schema:
- Edit
apps/server/src/db/schema/* - Run
bun run db:generate - Commit and push
Keep the route to service to query boundaries when adding features. An oxlint rule enforces that only src/db touches Drizzle.