This is a template for bootstrapping a Supabase project. It's a modern TypeScript stack that combines React, TanStack Router, Hono, ORPC, and more.
- React - UI library
- TypeScript - Type safety and improved developer experience
- Vite - Fast build tool and dev server
- TanStack Router - File-based routing with full type safety
- TanStack Query - Data fetching and state management
- TailwindCSS - Utility-first CSS for rapid UI development
- shadcn/ui - Reusable UI components built on Radix UI
- Better-Auth - Authentication library
- Supabase JS - Supabase client library
- Expo - React Native framework for cross-platform mobile development
- Expo Router - File-based routing for React Native
- React Native - Mobile UI framework
- UniWind - TailwindCSS for React Native
- Better-Auth Expo - Authentication for mobile apps
- Hono - Lightweight, performant server framework
- Node.js - Runtime environment
- Better-Auth - Authentication server
- ORPC - Type-safe RPC framework with OpenAPI support
- TypeScript - Type safety
- ORPC - End-to-end type-safe RPC with automatic OpenAPI documentation
- Zod - Schema validation and type inference
- PostgreSQL - Database engine
- Supabase - PostgreSQL hosting and management
- Drizzle ORM - TypeScript-first ORM for database operations
- Drizzle Kit - Database migration and introspection tool
- Trigger.dev - Background job processing and task scheduling
- Turborepo - Optimized monorepo build system
- pnpm - Fast, disk space efficient package manager
For a comprehensive feature-by-feature comparison between Better Auth and Supabase Auth, see COMPARISON.md.
This section explains the rationale behind the key technology decisions in this project.
- Schema as Code: Drizzle allows managing database schema as TypeScript code, providing version control, code review, and better collaboration on database changes.
- Cross-Platform Compatibility: The same schema definitions can be used for transactions in Deno as well, providing flexibility across different runtime environments.
- AI-Friendly: Drizzle's schema definitions provide full context to AI tools, making it easier to get accurate code suggestions and assistance.
- Type Inference: Excellent TypeScript type inference ensures type safety throughout the application, reducing runtime errors and improving developer experience.
- Plugin Ecosystem: Better Auth's extensive plugin system offers unparalleled customization and extensibility compared to integrated authentication solutions. This allows for easy integration of additional features without modifying core authentication logic.
- OAuth Access Token Management: Better Auth handles OAuth access tokens as part of the authentication system itself, making it seamless to work with third-party services that require OAuth tokens.
- Payment Integration: The Stripe plugin makes it straightforward to integrate payment providers, handling customer creation, subscription management, and webhook processing out of the box.
- Passkey Support: If needed, we can easily integrate expo-passkey with Better Auth for modern WebAuthn-based authentication, providing a passwordless authentication option.
- Expo Support: Better Auth includes native Expo support via
@better-auth/expo, enabling seamless authentication in React Native applications.
- End-to-End Type Safety: ORPC provides full type safety from server to client, eliminating the need for manual API type definitions.
- Automatic OpenAPI Documentation: ORPC automatically generates OpenAPI/Swagger documentation from your route definitions.
- Multiple Transport Support: Supports both RPC-style calls and RESTful endpoints with the same type-safe interface.
- Zod Integration: Built-in Zod schema validation ensures runtime type safety and automatic request/response validation.
supabase-start/
├── apps/
│ ├── web/ # Web frontend (React + Vite + TanStack Router)
│ │ ├── src/
│ │ │ ├── app/ # TanStack Router routes
│ │ │ ├── modules/ # Feature modules (auth, posts, etc.)
│ │ │ ├── shared/ # Shared components and utilities
│ │ │ └── main/ # App initialization
│ │ └── package.json
│ ├── backend/ # Backend server (Hono + ORPC)
│ │ ├── src/
│ │ │ └── app.ts # Hono server setup with ORPC handlers
│ │ └── package.json
│ └── native/ # Mobile app (Expo + React Native)
│ ├── app/ # Expo Router routes
│ ├── components/ # React Native components
│ └── package.json
├── packages/
│ ├── auth/ # Authentication package (Better-Auth)
│ │ ├── src/
│ │ │ ├── better-auth.ts # Better-Auth configuration
│ │ │ └── jwt.config.ts # JWT plugin configuration
│ │ └── package.json
│ ├── api/ # API package (ORPC routers)
│ │ ├── src/
│ │ │ ├── routers/ # ORPC route definitions
│ │ │ ├── handlers/ # Route handlers
│ │ │ └── context.ts # Request context creation
│ │ └── package.json
│ ├── platform/ # Platform package (Supabase + Drizzle)
│ │ ├── src/
│ │ │ ├── schema/ # Drizzle schema definitions
│ │ │ ├── drizzle.ts # Drizzle database instance
│ │ │ └── database.types.ts # Generated database types
│ │ ├── supabase/
│ │ │ ├── migrations/ # Database migrations
│ │ │ └── signing_key.base # Base64 encoded signing key
│ │ ├── scripts/
│ │ │ └── generate-signing-key.ts
│ │ └── package.json
│ ├── trigger/ # Background jobs (Trigger.dev)
│ │ ├── src/
│ │ │ ├── tasks/ # Background task definitions
│ │ │ └── repository/ # Data access layer
│ │ └── package.json
│ └── config/ # Shared TypeScript configuration
│ └── package.json
├── package.json # Root package.json (monorepo config)
├── pnpm-workspace.yaml # pnpm workspace configuration
└── turbo.json # Turborepo configuration
- Node.js (v18 or higher)
- pnpm (v10 or higher) - Install with
npm install -g pnpm - Supabase CLI (for local development) - Install with
npm install -g supabase
-
Clone the repository and install dependencies:
git clone <repository-url> cd supabase-start pnpm install
-
Generate signing key (inside platform package):
cd packages/platform pnpm run generate:signing-keyThis will create
signing_key.baseandsigning_key.jsonfiles inpackages/platform/supabase/. -
Set up environment variables:
- In
packages/auth/, create a.envfile (check for.env.exampleif available) - Add
SUPABASE_SIGNING_KEYtopackages/auth/.env:- Read the content from
packages/platform/supabase/signing_key.base - Add it as:
SUPABASE_SIGNING_KEY=<content-from-signing_key.base>
- Read the content from
- Add
CORS_ORIGINtopackages/auth/.env(e.g.,http://localhost:3001)
- In
-
Start Supabase local instance:
cd packages/platform pnpm run devThis will start the local Supabase instance and display the API URL and anon/public key.
-
Update environment variables:
- In
apps/web/.env, setVITE_SUPABASE_PUBLISHABLE_KEYto the anon/public key from step 4 - Also update
VITE_SUPABASE_URLwith the API URL from step 4 - In
apps/backend/.env, setCORS_ORIGIN(e.g.,http://localhost:3001)
- In
-
Reboot Supabase (after generating signing key):
cd packages/platform pnpm run supabase:resetThis stops and restarts the local Supabase instance to apply the new signing key.
-
Start development servers:
pnpm run dev
The web application will be available at http://localhost:3001 and the API/auth server will be running at http://localhost:3000.
To run the mobile app:
pnpm run dev:native
# or
cd apps/native
pnpm run devThis will start the Expo development server. You can then:
- Press
ito open iOS simulator - Press
ato open Android emulator - Scan QR code with Expo Go app on your device
This project uses Drizzle ORM combined with Supabase for managing database migrations. This combination allows for easy migration management and database resets.
Option 1: Custom migration (for seed data or custom SQL):
cd packages/platform
pnpm run db:generate:custom --name=create-bucketOption 2: Schema-based migration (recommended for schema changes):
- Update the schema files in
packages/platform/src/schema/ - Generate migration from root:
Or from the platform package:
pnpm run db:generate
cd packages/platform pnpm run db:generate
To apply migrations to the database:
pnpm run db:migrateOr from the platform package:
cd packages/platform
pnpm run db:migrateTo open Drizzle Studio for database inspection:
pnpm run db:studioTo reset the database to a fresh state (useful during development):
cd packages/platform
pnpm run db:resetThis will drop all tables and reapply all migrations from scratch.
pnpm run dev- Start all applications in development modepnpm run build- Build all applicationspnpm run dev:web- Start only the web applicationpnpm run dev:server- Start only the backend serverpnpm run dev:native- Start only the native mobile apppnpm run check-types- Check TypeScript types across all appspnpm run db:generate- Generate database migrations from schemapnpm run db:migrate- Apply database migrationspnpm run db:push- Push schema changes directly to database (development only)pnpm run db:studio- Open Drizzle Studio for database inspection
pnpm run generate:signing-key- Generate JWT signing key for Supabasepnpm run dev- Start Supabase local instancepnpm run supabase:reset- Stop and restart Supabase local instancepnpm run db:generate- Generate database migrations from schemapnpm run db:generate:custom- Generate custom migration (for seed data or custom SQL)pnpm run db:migrate- Apply database migrationspnpm run db:reset- Reset database to fresh statepnpm run db:studio- Open Drizzle Studiopnpm run generate:database-types- Generate TypeScript types from database schema
pnpm run dev- Start backend server in development modepnpm run build- Build backend serverpnpm run start- Start production serverpnpm run check-types- Check TypeScript types
pnpm run check-types- Check TypeScript typespnpm run auth:generate- Generate Better Auth schema types
pnpm run dev- Start web app in development mode (port 3001)pnpm run build- Build web app for productionpnpm run serve- Preview production buildpnpm run check-types- Check TypeScript types
pnpm run dev- Start Expo development serverpnpm run start- Start Expo development serverpnpm run android- Run on Android emulatorpnpm run ios- Run on iOS simulatorpnpm run web- Run in web browserpnpm run prebuild- Generate native projects
This project is designed to be deployed on Vercel:
- Web App (Frontend): Deploy using Vite on Vercel
- Auth Server (Backend): Deploy using Hono on Vercel
-
Connect your repository to Vercel
-
Configure build settings:
- Root directory: Leave as default (or set to project root)
- Build command:
pnpm run build - Output directory: Set per app (e.g.,
apps/web/distfor web app) - Install command:
pnpm install
-
Set environment variables in Vercel:
- Add all required environment variables from
.env.examplefiles - For production, use your production Supabase credentials
- Ensure
CORS_ORIGINis set to your production frontend URL
- Add all required environment variables from
-
Deploy:
- Vercel will automatically detect and deploy both the frontend and backend
- The backend server (Hono) will be deployed as Vercel Functions
- The web app (Vite) will be deployed as static assets with client-side routing
- ORPC endpoints will be available at
/rpc/*and OpenAPI docs at/api-reference/*
For more details, refer to: