Production-ready fullstack starter β React + NestJS + Supabase + PostgreSQL + Auth + CRUD. TypeScript everywhere.
# 1. Clone the repo
git clone https://github.com/guyboireau/fullstack-starter.git && cd fullstack-starter
# 2. Install all dependencies
npm install
# 3. Configure environment variables
cp .env.example .env # Then fill in your Supabase credentials
# 4. Start the dev servers
npm run devFrontend β http://localhost:5173 Β |Β API β http://localhost:3000
fullstack-starter/
βββ apps/
β βββ web/ β React 19 + Vite 6 + React Router 7
β βββ api/ β NestJS 11 (REST API)
βββ supabase/
β βββ migrations/ β SQL migrations (profiles, items)
β βββ seed.sql β Sample data
βββ docker-compose.yml
βββ .github/workflows/ci.yml
How it works: The React frontend authenticates users via Supabase Auth (email/password). Authenticated requests hit the NestJS API, which validates JWTs using a custom SupabaseAuthGuard. All database operations go through Supabase's client library with Row Level Security (RLS) β each user can only access their own data. The API uses a user-scoped Supabase client that respects RLS policies automatically.
| Feature | Details |
|---|---|
| π Authentication | Login, Register, Logout via Supabase Auth |
| π CRUD | Full Create, Read, Update, Delete on Items |
| π‘οΈ Auth Guard | NestJS guard validates Supabase JWTs |
| π Row Level Security | PostgreSQL RLS β users only see their own data |
| π¨ Modern UI | Dark mode, glassmorphism, gradient accents |
| π Dashboard | Stats overview + item management |
| β Validation | DTOs with class-validator on the API |
| π³ Docker Compose | One-command local dev environment |
| π CI/CD | GitHub Actions: lint + typecheck on every PR |
| π¦ Monorepo | npm workspaces β single npm install |
| Column | Type | Description |
|---|---|---|
id |
UUID (PK) | References auth.users |
email |
TEXT | User email |
full_name |
TEXT | Display name |
avatar_url |
TEXT | Profile picture URL |
created_at |
TIMESTAMPTZ | Auto-set |
| Column | Type | Description |
|---|---|---|
id |
UUID (PK) | Auto-generated |
user_id |
UUID (FK) | Owner reference |
title |
TEXT | Item title |
description |
TEXT | Optional details |
status |
TEXT | todo | in_progress | done |
created_at |
TIMESTAMPTZ | Auto-set |
All endpoints under auth require a Bearer token in the Authorization header.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/auth/profile |
β | Current user profile |
GET |
/users/me |
β | User profile from DB |
GET |
/items |
β | List all items |
GET |
/items/:id |
β | Get single item |
POST |
/items |
β | Create item |
PATCH |
/items/:id |
β | Update item |
DELETE |
/items/:id |
β | Delete item |
- Import the
apps/webdirectory on Vercel - Set the Root Directory to
apps/web - Add environment variables:
VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEY - Deploy π
- Create a new service on Railway or Render
- Set the Root Directory to
apps/api - Build command:
npm run build - Start command:
node dist/main - Add environment variables from
.env.example
- Create a new project at app.supabase.com
- Go to SQL Editor and run the migration files in order:
supabase/migrations/00001_create_profiles.sqlsupabase/migrations/00002_create_items.sql
- Copy your project URL + anon key from Settings β API
- Paste them in your
.envfile
# Start all services (PostgreSQL + API + Web)
docker compose up -d
# View logs
docker compose logs -f
# Stop everything
docker compose downThis isn't a tutorial copy-paste β it's the production stack I use for real client projects:
- Niido β Rental management platform
- La Lucarne β Real estate agency
- Les Cours de Clara β Online tutoring platform
MIT β use it, fork it, build with it.
