Auth, fully wired
Email/password register & login, Google OAuth, password reset via SMTP, DB-backed sessions, CSRF tokens, and rate limiting — all working out of the box.
Laju Go is a high-performance SaaS boilerplate. “Laju” means speed in Indonesian and Malay — and that is the entire point: a single binary you can deploy to a $5 VPS that serves a full SPA, authenticates users, accepts uploads, and runs migrations on startup. No container orchestration required, no separate API to maintain, no ORM fighting you at 2 a.m.
The stack is deliberately small and deliberately boring:
Everything you need to ship a SaaS is wired end to end: register/login, Google OAuth, password reset, DB-backed sessions, CSRF, rate limiting, avatar uploads, TUS large-file uploads, Goose migrations, tests, and a multi-stage Dockerfile.
Auth, fully wired
Email/password register & login, Google OAuth, password reset via SMTP, DB-backed sessions, CSRF tokens, and rate limiting — all working out of the box.
Uploads, two flavors
Multipart FormData for avatars, and the TUS protocol (via tusdfiber) for resumable large-file uploads.
Type-safe data layer
Write SQL in queries/*.sql, run sqlc generate, get fully typed Go. No stringly-typed query builders, no runtime reflection.
SPA without an API
Inertia.js drives Svelte 5 pages from the server. useForm + <form> for CRUD — no fetch boilerplate, no client-side routing to maintain.
Migrations on startup
Goose runs automatically when the binary starts. One table per migration file, never edit a deployed migration.
Deploy anywhere
Multi-stage Dockerfile, plus a make build-linux target that cross-compiles via Zig for CGO/SQLite.
A single Go binary is the entire backend. The frontend is built by Vite into dist/, which the Go binary serves using a Vite manifest.
flowchart LR Browser[Svelte 5 + Inertia] -->|HTTP| Fiber[Go Fiber] Fiber --> Routes[routes/web.go] Routes --> Handlers[app/handlers] Handlers --> Services[app/services] Services --> Queries[app/queries\nsqlc-generated] Services --> Cache[app/cache\nin-memory] Queries --> SQLite[(SQLite\nWAL mode)] Fiber -->|serves| Dist[dist/\nVite build]The one rule that holds the whole thing together: Handler → Service → Query → DB. No layer skips another. See the three-tier rule for why.
The fastest way in is the installer. It clones the template, strips dev-only files, installs Go and Node dependencies, and copies .env.example to .env:
npm create laju-go@latest my-appcd my-appnpm run dev:alldev:all runs Vite (frontend, port 5173) and Air (Go backend, port 8080) concurrently. Open http://localhost:8080 — the Go server proxies Vite in development.
Prefer to run from a clone of the repo? See Installation.