Monorepo template for creating a modern web application.
- Frontend: Svelte 5 + SvelteKit + TypeScript + Tailwind CSS 4 + shadcn-svelte + Lucide Svelte + Superforms + Valibot
- API: Supabase (PostgreSQL, Auth, Realtime, Storage)
- Build System: Turborepo + Bun + Vite
- Quality Tools: ESLint 9, Prettier, CSpell, markuplint
- Development: VS Code extensions, lint-staged, husky, GitHub Actions
api- Supabase Local Development PostgreSQL database, authentication, and API servicesweb[Demo] - SvelteKit Frontend Modern web application with page-based component organization, class-based design patterns, and comprehensive Supabase integrationpages[Demo] - Static Site Publishing High-quality static websites with URL validation, accessibility checks, and SEO optimization
shared- Shared components, styles, types, constants, and utilities- UI Components: shadcn-svelte components and custom components
- Styles:
app.css- Base Tailwind CSS styles - Shared logic: Types, constants, and utility functions
eslint-config- Centralized ESLint 9 configuration with Flat Config- Pre-configured setups:
root,web(Svelte),pages(Vanilla JS) - eslint-config-prettier - Prettier integration
- eslint-plugin-svelte - Svelte linting
- eslint-plugin-simple-import-sort - Import sorting
- eslint-plugin-jsdoc - JSDoc validation
- eslint-plugin-unused-imports - Unused import cleanup
- Pre-configured setups:
graph TB
subgraph "Monorepo Structure"
subgraph "apps/"
web["web<br/>SvelteKit App"]
pages["pages<br/>Static Site"]
api["api<br/>Supabase"]
end
subgraph "packages/"
shared["shared<br/>Components & Utils"]
eslint["eslint-config<br/>Linting Rules"]
end
web --> shared
web --> api
web --> eslint
pages --> eslint
shared --> eslint
end
subgraph "External Services"
supabase["Supabase Cloud<br/>Production DB"]
end
api -.-> supabase
# Install dependencies (.env file is created automatically)
bun install
# For static site development
bun --filter pages dev
# For web app development
bun --filter api start # Start Supabase API
bun --filter api generate # Generate TypeScript types (only when schema changes)
bun --filter web dev # Start web development serverNote: TypeScript types are committed to the repository, so you only need to run
generatewhen the database schema changes.
After running bun install, a .env file is automatically created from .env.example. Fill in the required values:
For local development:
PUBLIC_SUPABASE_URL-http://127.0.0.1:54321PUBLIC_SUPABASE_ANON_KEY- Copy the anon key displayed when runningbun --filter api start
For production deployment:
PUBLIC_SUPABASE_URL-https://[project-id].supabase.coPUBLIC_SUPABASE_ANON_KEY- Get from Supabase Dashboard > Project Settings > API Keys
Optional (for advanced operations):
DATABASE_URL- Enablesbun --filter api push/pullto target production databaseSUPABASE_SERVICE_ROLE_KEY- Server-side admin access for Edge Functions, Webhooks (never use in browser!)
Run across every app and package from the repo root:
bun install # Install dependencies (.env file is created automatically)
bun run dev # Start all development servers
bun run build # Build all apps and packages
bun run check # Type-check all apps
bun run lint # Lint all apps and packages
bun run format # Format all apps and packages
bun run test # Run all testsUse
bun run <script>, not barebun <script>— names likebuildandtestwould otherwise launch Bun's built-in bundler and test runner instead of the package script.
Run a package's own script directly with Bun's filter — use this for most day-to-day package commands:
bun --filter api start # Start Supabase API (port 54321)
bun --filter api generate # Regenerate API types after schema changes
bun --filter web dev # Start the web app only (port 5173)
bun --filter pages dev # Start the static site only (port 3000)
bun --filter pages deploy # Deploy the static siteScope a graph task to one package with Turbo when you specifically want dependency-aware execution and caching. Always use turbo run <task> (the bare turbo <task> shorthand clashes with built-in commands like generate):
bun turbo run build --filter web # Build only web (and its dependencies)
bun turbo run check --filter web # Type-check only web
bun turbo run generate --filter api # Regenerate API types with Turbo cachingcd apps/api
bun run start # Start Supabase locally
bun run stop # Stop Supabase
bun run status # Show Supabase service status
bun run reset # Reset database and regenerate types
bun run generate # Generate TypeScript types
bun run test # Run Supabase tests
bun run lint # Run linting
bun run format # Format codecd apps/web
bun run dev # Start development server (port 5173)
bun run build # Build for production
bun run preview # Preview production build
bun run check # Run type checking with svelte-check
bun run check:watch # Type checking in watch mode
bun run test # Run tests
bun run test:watch # Run tests in watch mode
bun run lint # Run linting
bun run format # Format codecd apps/pages
bun run dev # Start development server (port 3000)
bun run build # Build static site with Tailwind CSS
bun run test # Validate links, images, and accessibility
bun run test:watch # Run tests in watch mode
bun run test:update # Update test snapshots such as tests/external-links.txt
bun run lint # Run HTML validation with markuplint
bun run format # Format with Prettier
bun run deploy # Deploy public/ to DEPLOY_TARGET with rsync
# Optimization Utilities
bun run add-size-to-img # Add width/height to <img> tags for better performance
bun run clean-images # Remove unused images from project
bun run clean-images --dry-run # Preview unused image removals| Service | Port | Description |
|---|---|---|
| Supabase API | 54321 | REST API, GraphQL, Storage |
| Supabase DB | 54322 | PostgreSQL database |
| Supabase Studio | 54323 | Admin dashboard |
| Supabase Inbucket | 54324 | Email testing |
| Web App | 5173 | SvelteKit development server |
| Pages | 3000 | Static site with BrowserSync |
TypeScript types are automatically generated from your Supabase database schema:
- Local Development: Types are generated to
apps/api/$generated/types.ts - Frontend Usage: Types are imported from the
apipackage (e.g.,import type { Database } from 'api/types') - After Schema Changes: Run
bun --filter api generateto update types
Common components, types, and constants are imported from the @repo/shared package. See packages/shared for the available exports and usage examples.
You can easily switch between development and production environments:
- For Development: Use local Supabase (started with
bun --filter api start) - For Production Testing: Update
.envwith production Supabase credentials - Type Safety: Types are committed to repository for CI/CD compatibility
The project supports deploying both apps as separate Vercel projects. Each app includes its own vercel.json configuration file.
Configuration:
- Framework Preset: SvelteKit
- Root Directory:
apps/web - Build Command: Automatically configured via
apps/web/vercel.json - Install Command: Automatically configured via
apps/web/vercel.json
Environment Variables: Set the following environment variables in your Vercel project settings:
PUBLIC_SUPABASE_URL=https://your-project.supabase.co
PUBLIC_SUPABASE_ANON_KEY=your-anon-key- Framework Preset: Other
- Root Directory:
apps/pages - Build Command: Automatically configured via
apps/pages/vercel.json - Install Command: Automatically configured via
apps/pages/vercel.json - Output Directory:
public
- Use
bun run deploycommand inapps/pages - Configure
DEPLOY_TARGETinapps/pages/commands/deploy.js - Ensure SSH access and rsync are available for your target server
- Direct file transfer to your server
- Create two separate Vercel projects from the same GitHub repository
- Set different Root Directory for each project:
- Web App:
apps/web - Static Pages:
apps/pages
- Web App:
- Each project will use its respective
vercel.jsonconfiguration - Configure environment variables for the web app project
See CHANGELOG.md for highlights of notable and breaking changes. For the complete history, see the GitHub Releases.