Wafts is a Bun first TanStack Start template for building authenticated full-stack React apps with a vertical codebase structure.
This repository follows the TanStack Start - Build from Scratch guide for initialization.
Refer to this 1st commit for the exact code based on that guide.
Note that we will be using Bun throughout this repo. So kindly Install Bun if you haven't. PostgreSQL and Redis are also required, and you can run them using your preferred method (local, Docker, or managed service).
- TanStack Start with React 19 and a Bun first development workflow.
- Better Auth setup for authentication.
- Drizzle ORM with PostgreSQL.
- Redis via
ioredis. - An example authenticated app flow and feature domain that you can adapt or replace.
- shadcn/ui-style design-system primitives in
src/design-system. - Tailwind CSS v4, animation utilities, theme initialization, and toast support.
- Reusable route error UI in
src/errors. - Bun based scripts, Oxlint, Oxfmt, Simple Git Hooks, and Nano Staged for local formatting and linting.
src/
auth/ Better Auth server/client setup, auth schema, and auth server functions
db/ Drizzle Postgres client, Redis client, and schema aggregation
design-system/ shadcn/ui components, design-system utilities, and UI primitives
errors/ reusable app error helpers and route error UI
posts/ example feature domain with schema, client validation, and server functions
routes/ TanStack Router/Start route files and Better Auth API catch-all route
env.ts validated runtime environment schema
router.tsx router factory and default route error/not-found components
styles.css Tailwind, shadcn theme tokens, fonts, and global stylesbun devstarts the Vite/TanStack Start dev server on port 3000.bun run buildcreates a production build.bun run startpreviews the built app with Vite.bun run db:pushpushes the Drizzle schema to PostgreSQL.bun run db:studioopens Drizzle Studio.bun run auth:generateregenerates the Better Auth schema intosrc/auth/schema.ts.bun run lintandbun run fmt:checkcheck code quality and formatting.
This repo includes an AGENTS.md file for coding agents that documents project conventions, including repo structure, import style, and form submission patterns. Until we have proper human facing docs, you can refer to that file first before making code changes or contributing.
- Clone this repo
bunx gitpick bryanprimus/wafts- Install Dependencies
bun i- Setup Environment Variables
cp .env.example .env.localNote: Open
.env.localand configure yourDATABASE_URLandREDIS_URL. This template assumes you have PostgreSQL and Redis running locally or hosted elsewhere. Also replaceBETTER_AUTH_SECRETwith a unique secret of at least 32 characters and keepBETTER_AUTH_URLaligned with the app URL, such ashttp://localhost:3000in development.Runtime environment variables are validated in
src/env.ts. Add new variables there and keep.env.exampleupdated when the app needs more configuration.
Optional: Quick Setup with Docker
If you don't have Postgres and Redis installed locally, you can choose one of the two methods below to run them via Docker:
Create a compose.yaml file in the root of your project with the following content:
services:
postgres:
image: postgres:18.3-alpine3.23
ports:
- '5432:5432'
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: wafts_password
POSTGRES_DB: wafts
PGDATA: /var/lib/postgresql/data
volumes:
- pgdata:/var/lib/postgresql
redis:
image: redis:8.6.2-alpine
ports:
- '6379:6379'
volumes:
pgdata:Then, run the containers:
docker compose up -dIf you prefer not to create a compose.yaml file, you can start the containers directly from your terminal:
for postgres:
docker run -d --name wafts-postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=wafts_password -e POSTGRES_DB=wafts -e PGDATA=/var/lib/postgresql/data -p 5432:5432 -v pgdata:/var/lib/postgresql postgres:18.3-alpine3.23and then for redis:
docker run -d --name wafts-redis -p 6379:6379 redis:8.6.2-alpineTo stop and remove these containers later:
docker rm -f wafts-postgres wafts-redisIf you also want to completely wipe the Postgres database data, remove the volume:
docker volume rm pgdataNote for both options: You can freely customize the ports, username, database name, and password based on your needs. Just ensure that the
DATABASE_URLandREDIS_URLin your.env.localaccurately reflect your final choices!Example: If you change the Postgres port to
5438and the password tomy_secret_passin yourcompose.yamlordocker runcommand, your.env.localshould be updated to align:DATABASE_URL=postgresql://postgres:my_secret_pass@localhost:5438/wafts
- Push Database Schema
bun run db:push- Run the Development Server
bun dev