[App Name] · Go + HTMX
A Go web app. Server-rendered HTML, HTMX for partial updates, SQLite for state. Single binary, single deploy.
Source of truth
GitHub. CI builds a single static binary (CGO_ENABLED=0 GOOS=linux). The deployed binary is canonical. SQLite file is included in the volume; nightly backup to S3.
Tech stack
Go 1.23+ + chi for routing + templ for typed templates + HTMX for interactivity + Alpine.js (only where HTMX falls short). SQLite via mattn/go-sqlite3 (or modernc.org/sqlite for pure Go). Tailwind v4 via the standalone CLI (no Node). Litestream for SQLite replication.
Deploy
- Build:
go build -o bin/app ./cmd/server - Run:
./bin/app(port 8080) - Production: systemd service + Caddy in front for TLS. OR Fly.io with a single VM and persistent volume.
- Backups: Litestream replicates SQLite to S3 continuously.
File map
cmd/server/main.goserver entrypoint, HTTP setupinternal/handlers/chi handlers, one per resourceinternal/views/*.templtemplates (compiled to Go viatempl generate)internal/db/sqlc queries (typed Go from SQL) OR rawdatabase/sqlinternal/middleware/auth, logging, request IDmigrations/numbered SQL migrations applied viagoosestatic/JS (htmx, alpine), CSS (compiled Tailwind), imagesCaddyfilereverse proxy config (production)
.env keys
DB_PATHdefault./data/app.dbPORTdefault 8080SESSION_SECRETrandom 32-byte hexS3_BUCKET,S3_ACCESS_KEY,S3_SECRET(Litestream)ENVdev|prod
Hard rules
- Templates are
.templfiles compiled withtempl generate. Never edit generated.templ.gofiles. - SQLite is single-writer. Don't run multiple processes against the same DB file. Litestream is for backup, not for distribution.
- HTMX swaps are SCOPED. Every endpoint returns a fragment that exactly matches the swap target. Don't return full pages and then style-hide chunks.
- Migrations via
goose up. Migration files are immutable once shipped to prod. - Session cookie is httpOnly, secure, sameSite=lax. Random 32-byte token, NOT a JWT.
- Single binary deploy. No
node_modules. Novendor/committed unless you have a hard reason.
Recent significant changes
- 2026-05-11: Scaffolded. Locked: templ over html/template (type safety), HTMX over full SPA (boring is good), Litestream over manual backups (works while you sleep).
Next session: start here
templ generateto compile templates. Set up amaketarget so this runs on every save.goose -dir migrations create init sqland write your first schema.- Implement first resource: handler + template + SQL query. Click through it.
- Set up Litestream pointing at S3. Confirm a backup appears within 10 minutes.
- Deploy to a single Fly VM with a persistent volume. Confirm restart doesn't lose data.