The boring parts of a SaaS, already built.
A free, open-source SvelteKit SaaS boilerplate / starter template: authentication, organizations, multi-tenancy, transactional email, image uploads, a themed component library and a worked CRUD example — so your first commit is your product, not your plumbing.
Quickstart · Features · Deploy · Architecture · Building with AI agents · Contributing
The screenshots show the template exactly as it clones — “MyApp” is the placeholder in src/lib/config.json, one line away from your own name.
| Sign in | Tasks (the CRUD example) |
|---|---|
![]() |
![]() |
![]() |
![]() |
Component gallery — every element ships with a live reference page at /components:
- Auth that works without JavaScript — Better Auth with email + password, email verification, password reset, and optional Google/GitHub OAuth. Every flow is a progressively-enhanced form.
- Organizations & multi-tenancy — workspaces with roles, invitations and an org switcher. Every query is scoped to the active organization, including bulk writes.
- Remote functions only — the single client↔server data path is SvelteKit remote functions; every one starts with an authorization guard.
- A worked CRUD example —
/crudis a task list with search, filters, sorting and "load more", where the entire list state lives in the URL. Copy the pattern for your own models. - Component library —
Button,Field,Modal,DataTable,Toasterand friends on Tailwind 4 + daisyUI 5, with light/dark themes and a live gallery at/components. - Transactional email — Resend with one consistent message shape; without an API key every mail is printed to the terminal, so local sign-up just works.
- Image uploads — every upload goes through sharp into preset-sized WebP, served with a session gate and path-traversal checks.
- Typed everything — Prisma 7 (Postgres), Zod, explicit environment variable declarations, strict TypeScript, ESLint + Prettier.
- Tested — unit, browser component and HTTP integration tests, all running in CI.
You need bun and a Postgres. No Postgres at hand? bunx prisma dev starts a local one and prints the connection URL.
bun install
cp .env.example .env # set DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL
bun run db:migrate # apply migrations
bun run db:seed # demo users, two organizations, a task list
bun run devBETTER_AUTH_SECRET signs the session cookie — generate one with openssl rand -base64 32.
BETTER_AUTH_URL has to be the origin the app is reachable at, port included; the links in
verification and invitation emails are built from it, and the app refuses to start without it
outside development.
Leave RESEND_API_KEY empty to start: every email is then printed to the terminal instead of
sent, which is what makes signing up locally possible at all given that the address has to be
confirmed first. The seeded accounts skip that — sign in as owner@example.com with the
password demo-password.
- Name it —
app.nameinsrc/lib/config.json, plusnameinpackage.json. The logo, every page title, the footer and the workspace URL prefix read from there. - Brand it —
app.iconin the same file picks the logo mark (any name fromsrc/lib/components/elements/icons.ts); the two themes live insrc/lib/css/main.css. - Retell it — the landing copy, the panel beside the sign-in form and the navigation sit in
src/lib/config.jsonas well, so the public pages can be rewritten without touching a component. - Replace the demo content — the dashboard figures and billing plans still come from
src/lib/helper/demo.ts; delete an export there and follow the type errors. - Add your first model — copy the
/crudpattern: a Prisma model, a list config next tosrc/lib/helper/task.ts, a remote function, a page. The architecture guide walks through it.
| Script | Purpose |
|---|---|
bun run dev / build / preview |
Vite dev server / production build / preview |
bun run start |
Serve the production build (node build/index.js) |
bun run check |
svelte-check type checking |
bun run lint / format |
Prettier + ESLint / auto-format |
bun run test |
Vitest (unit + browser component tests) |
bun run test:integration |
HTTP integration tests against the production build (needs a DB) |
bun run db:migrate |
Create/apply Prisma migrations (development) |
bun run db:deploy |
Apply committed migrations (production/CI) |
bun run db:generate |
Regenerate the Prisma client into src/generated |
bun run db:seed |
Seed demo users, organizations and tasks (skips when there are users) |
bun run db:studio |
Prisma Studio |
Three layers, all running in CI:
- Unit tests — colocated
*.spec.tsnext to the helpers they test. - Component tests —
*.svelte.spec.tsin real Chromium via Vitest browser mode. - Integration tests —
tests/integration/boots the production build against a real Postgres and exercises sign-in, the auth wall and the seeded workspace over plain HTTP:bun run build && bun run test:integration.
The repo ships a railway.json that builds with bun, runs
prisma migrate deploy before each deployment and serves build/index.js. After clicking the
button (or creating a service from your fork):
- Add a Postgres to the project and reference its URL:
DATABASE_URL = ${{Postgres.DATABASE_URL}}. - Set the secrets —
BETTER_AUTH_SECRET(openssl rand -base64 32), and point bothBETTER_AUTH_URLandORIGINat your public origin, e.g.https://${{RAILWAY_PUBLIC_DOMAIN}}. - Attach a volume and set
UPLOAD_DIRto its mount path, e.g./data/uploads— anything inside the app directory is wiped on the next deployment, along with every avatar and logo.
Details, other platforms and the sharp caveat: docs/DEPLOYMENT.md.
This template is written to be worked on by AI coding agents — the conventions are few, explicit and machine-checkable:
- AGENTS.md — the contract: architecture rules, guardrails and the commands an
agent should run before calling anything done.
CLAUDE.mdpoints Claude Code at the same file. - Svelte MCP server —
.mcp.jsonconnects agents to the official Svelte MCP server for current Svelte 5 / SvelteKit docs and an autofixer, so agents don't write Svelte 4 from memory. - Guarded by design — authorization lives in
src/lib/server/guard.tsand every remote function starts with it; the layering means a generated feature is safe by construction, not by review. - Types as the safety net — deleting a demo export or renaming a field produces type errors that lead an agent through every affected file.
- Architecture — remote functions, auth, multi-tenancy, uploads, email, theming, lists.
- Deployment — Railway step by step, environment variables, migrations.
- Contributing — dev setup, checks, how to get a PR merged.
- AGENTS.md — the guide AI coding agents (and new humans) should read first.
Found a bug, a rough edge in the docs, or a pattern that deserves to be in the template? PRs and issues are very welcome — this project grows by being used. Good first contributions: another OAuth provider, a Stripe-backed billing page to replace the demo plans, more list configs, an S3-compatible upload target, translations of the content pages. See CONTRIBUTING.md to get started — the whole test suite runs with two commands, so you'll know quickly whether your change holds.
If tstack saved you a week of plumbing, a ⭐ on the repo helps others find it.
MIT — use it, fork it, ship your SaaS with it.




