Getting started
Breeze is a modern, high-performance Go web framework for people who want speed and a real toolbox: a router, WebSockets, request binding, an OpenAPI generator, a live developer dashboard, an event bus, durable workflows, distributed tracing across services, a JSON-RPC server, an AI-agent control plane โ all first-party, all documented, none of it bolted on as an afterthought.
It is built on gnet: one event loop per
core, zero-copy where it counts.
Installation
Requires Go 1.25.13 or later.
go get github.com/nelthaarion/breeze/v2 This pulls in gnet v2 for the event loop, go-json for fast marshaling, brotli for compression, and golang-jwt for authentication. Nothing else โ every other subsystem is an opt-in subpackage you import only if you use it.
Quick start
A complete server in under 20 lines:
package main
import (
"runtime"
"github.com/nelthaarion/breeze/v2"
middleware "github.com/nelthaarion/breeze/v2/middlewares"
)
func main() {
router := breeze.NewRouter()
router.Use(middleware.RecoveryMiddleware())
router.Use(middleware.LoggingMiddleware())
router.Handle(breeze.GET, "/", func(ctx *breeze.Context) error {
return ctx.JSON(map[string]string{"status": "ok"})
})
router.Handle(breeze.GET, "/users/:id", func(ctx *breeze.Context) error {
return ctx.JSON(map[string]string{"id": ctx.Param("id")})
})
pool := breeze.NewEventLoopWorkerPool(runtime.NumCPU())
app := breeze.New(router, pool)
app.Run(3000, true) // port, multiCore
} go run main.go
# curl http://localhost:3000/ โ {"status":"ok"}
# curl http://localhost:3000/users/42 โ {"id":"42"} Two building blocks appear in every Breeze program: a *breeze.Router that
maps methods and paths to handlers, and a *breeze.WorkerPool that the *breeze.Breeze server uses for anything that blocks. NewEventLoopWorkerPool sizes the pool to the number of CPUs, which is the right default for
CPU-bound or short blocking work.
Graceful shutdown
Run blocks until the server is stopped; Stop stops it. The contract
mirrors net/http.Server.Shutdown โ a context bounds how long in-flight work
is given to finish, and whatever is left is closed:
app := breeze.New(router, pool)
go func() {
if err := app.Run(3000, true); err != nil {
log.Printf("breeze: %v", err)
}
}()
// SIGINT / SIGTERM
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Stop(ctx); err != nil {
log.Printf("breeze: unclean shutdown: %v", err)
}
pool.Shutdown(ctx) // Stop does not touch a pool it did not create What Stop does, in order:
| Step | Behaviour |
|---|---|
| 1 | New connections are refused immediately |
| 2 | Every WebSocket connection gets a Close frame with 1001 going away, and its handler's OnClose runs through the connection's ordered queue |
| 3 | Work already dispatched to the pool โ blocking routes, WebSocket callbacks โ is given until ctx is done |
| 4 | The listener closes, anything still connected is force-closed, and Run returns |
Stop returns nil on a clean stop, ctx.Err() when step 3 ran out of time
(the teardown still happens), and breeze.ErrNotRunning when there was
nothing to stop. It is idempotent, and when it returns, Run's goroutine has
already exited. Each *Breeze holds its own engine, so two servers in one
process stop independently; a stopped one is not reusable โ Run then
returns breeze.ErrServerStopped.
Docker
docker build -t breeze-example .
docker run --rm -p 3000:3000 breeze-example
# or
docker compose up --build Breeze itself is a library โ point BREEZE_TARGET at any main package in
your module to containerize your app:
docker build --build-arg BREEZE_TARGET=./cmd/dashboard-example -t my-app . Where to go next
- CLI & Scaffolding โ
breeze new,generate,add,routes,migrate - Packages at a Glance โ every importable subpackage, one row each
- Router & Handlers โ the HTTP core
- Examples โ a runnable program per subsystem, under
cmd/