/library / template-go-htmx-stack
templateWeb app

Go + Templ + HTMX (no-JS web app)

A web app in pure Go. Templ for typed templates, HTMX for interactivity, SQLite for state. Single static binary deploys anywhere. Use when you want simplicity, speed, and a stack that won't have a churn cycle every six months.

use whenInternal tool, content site, admin dashboard, or product where the team has a backend-heavy skillset and 'a build step' is a red flag.

May 11, 20262,210 bytesgohtmxtemplsqliteno-js

[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.go server entrypoint, HTTP setup
  • internal/handlers/ chi handlers, one per resource
  • internal/views/ *.templ templates (compiled to Go via templ generate)
  • internal/db/ sqlc queries (typed Go from SQL) OR raw database/sql
  • internal/middleware/ auth, logging, request ID
  • migrations/ numbered SQL migrations applied via goose
  • static/ JS (htmx, alpine), CSS (compiled Tailwind), images
  • Caddyfile reverse proxy config (production)

.env keys

  • DB_PATH default ./data/app.db
  • PORT default 8080
  • SESSION_SECRET random 32-byte hex
  • S3_BUCKET, S3_ACCESS_KEY, S3_SECRET (Litestream)
  • ENV dev | prod

Hard rules

  • Templates are .templ files compiled with templ generate. Never edit generated .templ.go files.
  • 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. No vendor/ 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

  1. templ generate to compile templates. Set up a make target so this runs on every save.
  2. goose -dir migrations create init sql and write your first schema.
  3. Implement first resource: handler + template + SQL query. Click through it.
  4. Set up Litestream pointing at S3. Confirm a backup appears within 10 minutes.
  5. Deploy to a single Fly VM with a persistent volume. Confirm restart doesn't lose data.

Get the next CLAUDE.md in your inbox.

One new template every week, plus occasional case studies.