A declarative HTTP server framework β describe your backend in YAML, ship a single binary.
Docs β’ Quickstart β’ Cookbook β’ For AI agents
storage:
app:
type: sqlite
path: ./data.db
tables:
users: { columns: ["id INTEGER PRIMARY KEY", "name TEXT NOT NULL"] }
routes:
- path: /users
method: POST
type: storage-access
inputs: [{ name: name, source: body, type: string, required: true, min: 1 }]
storage-access:
source: app
execute: "INSERT INTO users(name) VALUES ({{name}})"
output_template: '{"id": {{.LastInsertID}}}'wave serve server.yaml --port 8080
curl -X POST -d '{"name":"ada"}' http://localhost:8080/users
# {"id": 1}That's a working endpoint with input validation, parameterised SQL (no
injection possible), JSON response, and a built-in /healthz probe. No
Go code, no node_modules, no Docker Compose stack. The same server.yaml
deploys as a single binary or a 25 MB distroless container.
β Full feature inventory β every route type, middleware, CLI subcommand, plugin kind, in one searchable page.
| Count | What | |
|---|---|---|
| Route types | 28 | storage-access, task, match, forward, auth-login, magic-link-*, oauth-*, totp-*, webhook (with signature verify), stream-publish, schedule, process, plugin, graphql, file-server, β¦ |
| Demo apps | 64 | Self-contained server.yaml files under examples/apps/ β chat, polls, todo, pastebin, multi-tenant SaaS, Stripe receiver, SSE chat, photo gallery, OIDC, SAML, audit-logged admin, ML sidekick, β¦ |
| Cookbook recipes | 16 | Copy-paste patterns for the common needs |
| CLI commands | 11 | serve, test, validate, fmt, routes, doctor, init, migrate, outbox, completion, studio |
| Auth built-in | 6 | magic link, OAuth, OIDC, SAML (via plugin), TOTP 2FA, JWT |
| Webhook providers | 4 | Stripe, GitHub, Slack, generic HMAC β all with replay protection |
| Observability | 4 | Prometheus /metrics, OpenTelemetry traces, JSON access logs, append-only audit log |
| Reliability | 5 | Outbox CLI, circuit breaker, rate limiter, body-size limits, response cache |
| Deploy targets | 4 | macOS / Linux / Windows binaries + distroless Docker image |
Most backends are 80% boilerplate β request parsing, validation, DB calls, auth wiring, middleware ordering. Wave does that 80% declaratively. You write Go (or any language, as a plugin) only where it actually matters.
The same JSON API endpoint:
| Stack | Lines | Tokens |
|---|---|---|
| Wave | 13 | ~140 |
| FastAPI + Pydantic | 24 | ~360 |
| Gin (Go) | 38 | ~440 |
| Express + Zod + Prisma | 38 | ~520 |
More features per Cursor request, more state per Claude context window, fewer
hallucinations. Wave ships llms.txt, a Claude Code
skill, and a JSON Schema for server.yaml so AI
editors auto-complete and produce working configs first try. See
the full comparison.
- SQL injection: impossible. Every value goes through
{{name}} β ?parameterised binding. The framework rejects unsafe alternatives. - CSRF, webhook signatures (Stripe / GitHub / Slack), rate limits, circuit breakers, body-size limits, request-schema validation, secure headers β all wired into the middleware chain.
- RBAC via claims, forward auth for delegation, audit log for every mutation.
/healthz+/readyzbuilt in- Prometheus
/metrics+ OpenTelemetry traces - Outbox CLI for durable webhook delivery with retry + DLQ
- Migrations (
wave migrate up) - Doctor (
wave doctor --json) for pre-flight checks - Functional test runner (
wave test) β YAML-driven, in-process, no port
# server.test.yaml
import: server.yaml
tests:
- name: create user
request: { method: POST, path: /users, json: { name: ada } }
expect: { status: 200, json: { id: "*" } }
capture: { id: json.id }
- name: read it back
request: { method: GET, path: /users/{{.id}} }
expect: { status: 200, json: { name: ada } }wave test server.test.yaml --json # CI-friendly, in-process, no port bindingWave isn't a replacement for React, Node, or Python. It's a complement:
- React / Next.js + Wave backend β auth + persistence in YAML, your frontend stays on Vercel
- Wave in front of an Express service β gateway pattern for auth, rate-limit, audit, webhook signatures
- Wave + Python ML service β wrap a FastAPI/model server with auth + SSE + 202-task patterns
- Migrate from Express incrementally β route-at-a-time, no big-bang
The most-asked "how do I plug Wave into X?" recipes:
- Sign in with Google β OIDC, domain-gated
- Stripe Checkout (and webhooks)
- OpenAI / Claude / Ollama chat β streaming tokens via task + plugin
- Transactional email β Resend / SendGrid / Postmark / Mailgun
- SMS via Twilio β verify codes, 2FA, alerts
- Slack slash command β signature-verified, sub-3-second response
- S3 / R2 / B2 uploads β pre-signed PUT, bypass-Wave for bytes
- Firebase Cloud Messaging β iOS / Android / web push
- Supabase / Neon / Railway Postgres β managed Postgres via plugin
Same type: fetch / webhook_sig: / type: plugin primitives β once you've done one, the rest are copy-paste.
Don't see what you need? Build a plugin (any language) β same echo plugin in Go, Python, Node, Rust, and 9-line Bash.
| You are⦠| Start here |
|---|---|
| Trying it for the first time | Quickstart (5 min) |
| Building a real app | Tutorial: build a todo API (30 min) |
| An indie hacker | wave init api β scaffolded project with auth + Docker + Fly.io ready |
| A backend engineer | Comparison vs Express / FastAPI / Gin |
| A platform / SRE engineer | Production checklist + Observability |
| An AI agent builder | Token efficiency + Claude skill |
| Adding Wave to an existing app | Wave in your stack |
# Pre-built binaries (macOS / Linux / Windows)
curl -sSfL https://luowensheng.github.io/wave/install.sh | sh
# Pin a version
curl -sSfL https://luowensheng.github.io/wave/install.sh | sh -s -- v0.1.0
# Or via Go (latest main, includes built-in SQLite)
go install github.com/luowensheng/wave/orchestrator@latest
# Or via Docker (sqlite-capable)
docker run --rm -p 8080:8080 \
-v $(pwd)/server.yaml:/server.yaml \
ghcr.io/luowensheng/wave:latest serve /server.yaml --port 8080Released binaries are built
nosqlitefor cross-platform simplicity. Use the Docker image orgo installfor built-in SQLite. Homebrew formula lands shortly.
wave serve server.yaml --port 8080 # run a server
wave test server.test.yaml # run a YAML test suite
wave validate server.yaml # boot-time config check (no server)
wave fmt server.yaml --check # CI-safe yaml formatter
wave doctor server.yaml --json # live diagnostics
wave routes server.yaml --format=json # print the route table
wave init api ./my-project # scaffold a starter
wave migrate up --db ./data.db --dir ./migrations
wave outbox list --db ./outbox.db # operate the durable outbox
wave completion bash|zsh|fish # shell completiongit clone https://github.com/luowensheng/wave.git
cd wave
# Pick any of the 64 demos
go run ./orchestrator serve examples/apps/url-shortener/server.yaml --port 8102
curl http://localhost:8102/healthz
# {"status":"ok",β¦}
# Or run its test suite
go run ./orchestrator test examples/apps/url-shortener/server.test.yaml
# PASS [test] built-in /healthz returns JSON with status ok (200, 1ms)
# PASS [test] unknown path returns framework 404 envelope (404, 0s)
# PASS [test] POST /shorten validates slug pattern (400, 0s)
# β¦
# 8 passed, 0 failed, 0.00s- Not a frontend framework (it serves your React/Vue/Svelte build, but doesn't render it).
- Not a service mesh (it sits at L7, in your app; pair with Istio/Linkerd if you need mTLS).
- Not a workflow engine (it has a scheduler; use Temporal/Airflow if you need durable multi-step workflows).
- Not a replacement for your domain code β it's the boring parts done declaratively so you can focus on the parts that aren't.
- luowensheng.github.io/wave β docs site (45 pages)
- CLAUDE.md β full developer guide (architecture, conventions, every YAML key)
- docs/ β reference docs (storage, auth, plugins, composition, bundler)
- examples/apps/ β 64 runnable demos
- llms.txt β LLM-friendly index for AI agents
- GitHub Discussions β questions, ideas, show & tell
- Issues β bug reports and feature requests
- Discord β coming soon
Pre-1.0. Breaking changes are allowed between 0.x minors and are documented in CHANGELOG.md. Production usage is welcome β pin a version and read the CHANGELOG before upgrading.
Wave never phones home. No telemetry, no analytics, no remote config fetches. The single binary only contacts services you configure.
PRs welcome. Start with CONTRIBUTING.md for the process
and CLAUDE.md for the architecture. Good first issues:
good-first-issue.
Apache-2.0 β see LICENSE.