# Elysia + TanStack Dashboard - Blueprint (/docs/blueprints/elysia-tanstack-dashboard)



An opinionated starter for authenticated web products, built with [Elysia](https://elysiajs.com/) on [Bun](https://bun.sh/) and [TanStack Start](https://tanstack.com/start), managed as a [Turborepo](https://turborepo.dev/) monorepo. One repository, two services, one database.

**Tech stack:**

| Layer       | Technology                                                                                                         |
| ----------- | ------------------------------------------------------------------------------------------------------------------ |
| API         | Elysia on Bun, port 3001                                                                                           |
| Type safety | [Eden](https://elysiajs.com/eden/overview) - the web app imports the API *type*, no codegen, no shared DTO package |
| Auth        | [better-auth](https://better-auth.com/) cookie sessions, email and password, OIDC-ready                            |
| Database    | PostgreSQL + [Drizzle ORM](https://orm.drizzle.team/)                                                              |
| Web         | TanStack Start + TanStack Query + [shadcn/ui](https://ui.shadcn.com/) on Base UI, port 3000                        |

<a href="https://github.com/rock8-cloud/elysia-tanstack-dashboard-monorepo" target="_blank" rel="noopener noreferrer">
  View on GitHub →
</a>

***

## What You Get [#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 [#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.

<Callout type="warn">
  **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.
</Callout>

***

## Changing the API URL [#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 [#database-migrations]

Migrations run automatically when the API starts. To change the schema:

1. Edit `apps/server/src/db/schema/*`
2. Run `bun run db:generate`
3. Commit and push

Keep the route to service to query boundaries when adding features. An oxlint rule enforces that only `src/db` touches Drizzle.

***

## Related [#related]

* [Environment Variables](/docs/guides/environment-variables)
* [PostgreSQL](/docs/databases-and-storage/postgresql)
* [Blueprints](/docs/blueprint)
