A production-ready TypeScript monorepo starter kit with React 19, Express 5, Better Auth, and SQLite
- ποΈ Modern Monorepo Architecture - Turborepo + pnpm workspaces for blazing-fast builds
- βοΈ React 19 - Latest React with Vite 7 for lightning-fast development
- π Express 5 - Modern Express.js backend with TypeScript + ESM support
- π Authentication - Better Auth with email/password + Google OAuth out of the box
- πΎ Database - SQLite + Drizzle ORM with type-safe queries
- β Type Safety - Strict TypeScript everywhere with Zod validation
- π¨ Styling - Tailwind CSS 4.x for rapid UI development
- π Code Quality - ESLint 9 (flat config) + Prettier pre-configured
- π State Management - Tanstack Query for server state, React hooks for UI state
- π File-Based Routing - Tanstack Router with auto-generated route tree
- π‘οΈ Security - Helmet.js security headers + CORS configured
- β‘ Developer Experience - Single command to run everything (
pnpm dev)
- Node.js: v24.3.0+ (v22.13.1 minimum)
- pnpm: 10.13.1 (enforced via packageManager field)
- Platform: Linux/macOS/WSL (SQLite file-based database)
# Clone the repository
git clone <your-repo-url>
cd modern-monorepo-fullstack-kit
# Install dependencies
pnpm install
# Copy environment files
cp .env.example .env
cp apps/api/.env.example apps/api/.env
cp apps/app/.env.example apps/app/.env
# Generate database schema and run migrations
pnpm db:generate
pnpm db:migrate
# Start development servers (frontend + backend)
pnpm devThe application will be available at:
- Frontend: http://localhost:5173
- Backend API: http://localhost:8080
- Health Check: http://localhost:8080/api/health
modern-monorepo-fullstack-kit/
βββ apps/
β βββ api/ # Express.js backend (port 8080)
β β βββ src/
β β β βββ routes/ # API route handlers
β β β β βββ health.ts # Health check endpoint
β β β β βββ user.ts # Protected user routes
β β β βββ server.ts # Express app setup
β β βββ index.ts # Entry point
β β
β βββ app/ # React frontend (port 5173)
β βββ src/
β β βββ routes/ # File-based routes
β β β βββ __root.tsx # Root layout
β β β βββ index.tsx # Home page
β β β βββ auth/ # Auth pages (login, signup)
β β β βββ _protected/ # Protected routes
β β βββ modules/
β β β βββ auth/ # Auth module (hooks, layouts, pages)
β β βββ lib/
β β βββ api.ts # Axios client
β β
βββ packages/
β βββ auth/ # Better Auth configuration
β β βββ server.ts # Auth server setup
β β βββ client.ts # Auth client (React)
β β
β βββ config/ # Shared configuration
β β βββ index.ts # Environment config
β β
β βββ db/ # Database layer
β β βββ src/
β β β βββ db.ts # SQLite connection
β β β βββ schemas/ # Drizzle schemas
β β β β βββ auth.ts # Auth tables (user, session, etc.)
β β β βββ queries/ # Database queries
β β βββ drizzle.config.ts # Drizzle Kit config
β β
β βββ validator/ # Validation utilities
β β βββ src/
β β β βββ error.ts # Custom error classes
β β β βββ validator.ts # Zod middleware
β β β βββ neverthrow.ts # Result type helpers
β β βββ index.ts
β β
β βββ eslint-config/ # Shared ESLint configs
β βββ base.js # Base rules
β βββ typescript.js # TypeScript rules
β βββ react.js # React rules
β βββ node.js # Node.js rules
β
βββ turbo.json # Turborepo configuration
βββ pnpm-workspace.yaml # pnpm workspace config
βββ package.json # Root package.json
- React 19 - UI library
- Vite 7 - Build tool
- Tanstack Router - Type-safe routing
- Tanstack Query - Server state management
- Tailwind CSS 4 - Utility-first CSS
- React Hook Form - Form management
- Zod - Schema validation
- Express 5 - Web framework
- Better Auth - Authentication
- Drizzle ORM - Type-safe ORM
- SQLite - Database (WAL mode enabled)
- Helmet - Security headers
- CORS - Cross-origin resource sharing
- TypeScript 5.8 - Type system
- Turborepo - Build orchestration
- pnpm - Package manager
- ESLint 9 - Linting (flat config)
- Prettier - Code formatting
# Start both frontend and backend
pnpm dev
# Start individually
pnpm dev:api # Backend only (http://localhost:8080)
pnpm dev:app # Frontend only (http://localhost:5173)# Generate migration from schema changes
pnpm db:generate
# Apply migrations to database
pnpm db:migrate
# Open Drizzle Studio (visual DB editor)
pnpm db:studio # http://localhost:8082# Linting
pnpm lint # Check all workspaces
pnpm lint:fix # Auto-fix issues
# Formatting
pnpm format # Format all files
pnpm format:check # Check formatting (CI)
# Type checking
pnpm type-check # TypeScript validation# Build all packages for production
pnpm buildThis starter kit comes with Better Auth pre-configured with:
Ready to use out of the box. Users can sign up and sign in with email/password.
To enable Google OAuth:
- Create a Google Cloud Project at console.cloud.google.com
- Enable Google OAuth and create credentials
- Add your credentials to
.env:
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secretUse the _protected layout to protect routes:
// apps/app/src/routes/_protected/dashboard.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/_protected/dashboard')({
component: Dashboard,
});
function Dashboard() {
return <div>Protected Dashboard</div>;
}Use the authentication middleware:
// apps/api/src/routes/example.ts
import { authentication } from '@starter/auth/server';
router.get('/protected', async (req, res, next) => {
try {
const { user } = await authentication(req);
res.json({ user });
} catch (error) {
next(error);
}
});# Create new route file
touch apps/app/src/routes/about.tsx// apps/app/src/routes/about.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/about')({
component: AboutPage,
});
function AboutPage() {
return <div>About Page</div>;
}Route automatically available at: http://localhost:5173/about
// packages/db/src/schemas/posts.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey(),
title: text('title').notNull(),
content: text('content'),
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
});// packages/db/src/schemas/index.ts
export * from './auth';
export * from './posts'; // Add this line# Generate and apply migration
pnpm db:generate
pnpm db:migrate// apps/api/src/routes/posts.ts
import { Router, type Request, type Response } from 'express';
import { db } from '@starter/db';
import { posts } from '@starter/db/schemas';
const router = Router();
router.get('/', async (req: Request, res: Response) => {
const allPosts = await db.select().from(posts);
res.json(allPosts);
});
export { router as postsRouter };// apps/api/src/server.ts
import { postsRouter } from './routes/posts';
// Add to routes section
app.use('/api/posts', postsRouter);NODE_ENV=development
PORT=8080
HOST=localhost
APP_NAME=Starter Kit
APP_VERSION=0.1.0
FRONTEND_URL=http://localhost:5173
DATABASE_URL=./dev.db
# Optional - Google OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=VITE_API_URL=http://localhost:8080The project uses class-based errors for operational errors:
import { NotFoundError, ValidationError } from '@starter/validator';
// In route handler
if (!user) {
throw new NotFoundError('User not found');
}All endpoints should validate requests using Zod schemas:
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
name: z.string().min(2),
});
// Validate in handler
const data = schema.parse(req.body);For service layer code, use Result types:
import { ok, err, type AsyncResult } from '@starter/validator';
async function getUserById(id: string): AsyncResult<User> {
const user = await db.select().from(users).where(eq(users.id, id));
if (!user) return err(new NotFoundError('User not found'));
return ok(user);
}pnpm buildFrontend:
Backend:
Database:
- Turso - SQLite in the cloud
- Or migrate to PostgreSQL with minimal changes
For detailed documentation, see:
- CLAUDE.md - Comprehensive guide for AI assistants and developers
- Better Auth Docs - https://better-auth.com/docs
- Drizzle ORM Docs - https://orm.drizzle.team/docs
- Tanstack Router Docs - https://tanstack.com/router/latest/docs
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details
Built with amazing open-source projects:
- React, Express, TypeScript
- Better Auth, Drizzle ORM, Tanstack Router
- Turborepo, pnpm, Vite
Happy Coding! π
Made with β€οΈ