- Go 76.1%
- Go Template 16.1%
- TypeScript 4%
- CSS 1.6%
- Vue 1%
- Other 1.2%
| .github/workflows | ||
| app | ||
| assets/brand | ||
| auth | ||
| cache | ||
| cmd/serval | ||
| config | ||
| database | ||
| examples/demo | ||
| internal | ||
| log | ||
| queue | ||
| router | ||
| schedule | ||
| session | ||
| .gitignore | ||
| .golangci.yml | ||
| .goreleaser.yaml | ||
| .releaserc.yaml | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| go.mod | ||
| go.sum | ||
| install.sh | ||
| Makefile | ||
| README.md | ||
| serval.go | ||
| serval_test.go | ||
Serval
The batteries-included Go framework. One command to a working app with queues, cache, scheduling, sessions, auth, and typed TypeScript clients already wired — all of it idiomatic Go: chi routing, SQL-first sqlc queries, explicit DI via samber/do, errors as values rendered as RFC 9457 problem+json.
Part of the Caracal family: apps compile to a single static binary that deploys naturally onto Caracal Serve.
Install
curl -fsSL https://git.gasi.dev/caracal/serval/raw/branch/main/install.sh | bash
Detects your platform, verifies the release checksum, and installs to /usr/local/bin
(override with SERVAL_INSTALL_DIR, pin a version with SERVAL_VERSION=v0.2.0).
Alternatively: go install git.gasi.dev/caracal/serval/cmd/serval@latest.
Once installed, serval upgrade updates in place.
One command
serval new shop # interactive: API-only or full-stack, drivers, auth, UI kit
cd shop && serval dev --worker --scheduler
Fully scriptable — prompts auto-skip when stdin is not a terminal:
serval new billing --module=git.gasi.dev/acme/billing \
--auth=self --frontend=tanstack --ui=base --pm=bun --skills --git
The app binary is its own CLI
./shop serve # HTTP server (graceful shutdown, /healthz + /readyz probes)
./shop migrate # app migrations + framework schemas, embedded in the binary
./shop queue:work # background workers
./shop schedule:run # recurring tasks (pg advisory-lock leader election)
./shop routes # route table
./shop openapi # OpenAPI 3.1 from the typed routes (boots with zero config)
./shop key:generate | health | version
One distroless image runs every role — different argv per process type.
Batteries
| Subsystem | Drivers | Notes |
|---|---|---|
| Queue | River (Postgres) · asynq (Redis) · Cloudflare Queues | River: EnqueueTx commits jobs atomically with your data |
| Cache | hot (in-memory) · Postgres · Redis | cache.Remember[T] with singleflight dedup |
| Sessions | Postgres · Redis | HMAC-signed cookies, tokens hashed at rest |
| Auth | self-hosted (argon2id + API tokens) · Clerk | both yield the same auth.Principal |
| Scheduler | built-in | Cron/Every, WithoutOverlap, OnOneServer |
Every driver passes one shared conformance suite; swap with a .env flip.
Typed handlers → typed TypeScript clients
func (h *Users) Create(ctx context.Context, in CreateUserInput) (router.Created[db.User], error)
Binding (json/path/query/header tags), validation, and problem+json errors are
framework concerns. The same signature drives the API contract:
serval client # routes → openapi.json (committed) → Hey API → frontend/src/client
Rename a Go field and the TypeScript build breaks — at compile time, not in production.
Frontends
--frontend=tanstack (React 19, TanStack Start, Vite 7) or --frontend=nuxt (Nuxt 4),
both with Tailwind v4 and a dev proxy into the Go API. Pick the UI kit:
- shadcn (default, both) — pre-styled components,
npx shadcn add - Base UI (TanStack) — headless React primitives
- Nuxt UI (Nuxt) — 125+ official components
serval dev supervises Go rebuilds, sqlc generate on query changes, and the frontend
dev server (bun/pnpm/npm — your choice) in one prefixed log stream.
Inner loop
serval generate handler Orders # + the one registration line to paste
serval generate query orders # write SQL, then: serval sqlc
serval generate migration add_orders
serval generate job SendReceipt
serval dev # hot reload everything
Generators only create files — your code is never rewritten. --skills scaffolds
AGENTS.md + .claude/skills/ so AI coding agents know all of these conventions too.
Development (this repo)
make lint test build # local gate
make test-integration # needs DATABASE_URL / REDIS_URL
make e2e # generate → build → migrate → serve → assert
Requires the latest Go release (1.26+).