Full-stack Go framework.
Everything you need to build, ship, and run web applications — routing, ORM, authentication, cache, queues, mail, storage, real-time, and more. One binary. No external runtime. No Docker required for development.
Requires Go 1.26+.
Status: Pre-1.0 (currently v0.62.x). API is still in flux — breaking changes may occur between minor releases. See RELEASES.md for the versioning policy and CHANGELOG.md for per-release breaking-change notes.
brew install --cask velocitykode/tap/velocityvelocity new myapp --stack=react && cd myapp && ./vel serveOr add to an existing project:
go get github.com/velocitykode/velocity@latestpackage main
import (
"log"
"github.com/velocitykode/velocity"
"github.com/velocitykode/velocity/router"
)
func main() {
v, err := velocity.New()
if err != nil {
log.Fatal(err)
}
v.Router.Get("/", func(c *router.Context) error {
return c.JSON(200, map[string]string{"hello": "world"})
})
if err := v.Serve(); err != nil {
log.Fatal(err)
}
}Every subsystem is an importable subpackage. Pull in only what you need: you own the lifecycle, and you compile only what you import.
import "github.com/velocitykode/velocity/cache"
mgr := cache.NewManager(&cache.Config{
Default: "memory",
Stores: map[string]cache.StoreConfig{"memory": {Driver: cache.DriverMemory}},
})
mgr.Put("greeting", "hello", 5*time.Minute)
v, _ := mgr.Get("greeting") // "hello"See Standalone packages.
For larger apps, declare bootstrap concerns up-front and chain them.
The callbacks below live in your own app and routes packages —
velocity new scaffolds them for you, or you can write them by hand.
func main() {
v, _ := velocity.New()
if err := v.
Middleware(app.Middleware(v)). // your global/web/API middleware stacks
Routes(routes.Register). // your route definitions
Events(app.Events(v.Log)). // your event listeners
Schedule(schedule.Configure). // your scheduled jobs
Exceptions(app.ExceptionHandler). // your custom error handler
Run(); err != nil { // serves HTTP, or runs a `./vel ...` command
log.Fatal(err)
}
}User signs up, validation runs, the user is saved, a job goes onto the queue, and a typed JSON response comes back — all in one handler:
v.Router.Post("/signup", func(c *router.Context) error {
var input struct {
Email string `json:"email" validate:"required,email"`
Name string `json:"name" validate:"required"`
}
if err := c.Bind(&input); err != nil {
return c.BadRequest(err.Error())
}
user := models.User{Email: input.Email, Name: input.Name}
if err := user.Save(); err != nil {
return err
}
v.Queue.Push(jobs.SendWelcomeEmail{UserID: user.ID})
return c.JSON(201, user)
})Validation, ORM, queue, and router — designed to work together.
Generic models return []User, not []interface{}. Queries are
checked at compile time. If the types don't match, it doesn't build.
users, _ := User{}.Where("active = ?", true).
OrderBy("created_at", "DESC").
Limit(10).
Get()Queries · Relationships · Migrations
Every subsystem uses pluggable drivers configured through environment variables.
| Subsystem | Drivers |
|---|---|
| Database | PostgreSQL, MySQL, SQLite |
| Cache | Memory, File, Redis, Database |
| Queue | Memory, Redis, Database |
| Storage | Local, S3, Memory |
| Postmark, Mailgun, Local (writes to disk) | |
| Auth | Sessions, JWT (plus gates and policies on top) |
| Broadcasting | WebSocket (additional drivers planned) |
SQLite in development, PostgreSQL in production. One env var:
DB_CONNECTION=sqlite # or postgres, mysql
CACHE_DRIVER=redis # or memory, file, database
QUEUE_DRIVER=redis # or memory, database
STORAGE_DRIVER=s3 # or local, memory
MAIL_DRIVER=postmark # or mailgun, local, logSafe defaults you opt out of, not into. Cookies ship Secure, HttpOnly,
and SameSite=Lax. CORS rejects every cross-origin request until you name
the origins you trust. CSRF is on for every state-changing method. The app
won't start without an APP_KEY, and APP_DEBUG=true is ignored in
production so stack traces never leak. The destructive CLI commands
(db:wipe, migrate:fresh, migrate:rollback) refuse to touch a
production database unless you pass --force.
The lower-level pieces are conservative too:
| Area | Default |
|---|---|
| Crypto | AES-256-GCM, random nonces, constant-time compares, HKDF subkey separation |
| Passwords | bcrypt with an enforced cost floor |
| Auth | JWT rejects alg=none and algorithm substitution; session ID rotates on login |
| Tokens | 32-byte crypto/rand session and CSRF tokens |
| ORM | parameterized queries, validated identifiers, deny-by-default mass assignment |
| Storage | os.Root path containment (openat2 on Linux), no traversal or symlink escape |
| HTTP client | SSRF guard blocks private and link-local ranges by default, TLS 1.2 floor |
Security headers (HSTS, CSP), HTTPS redirect, and request throttling ship as
middleware you wire into the stack. Insecure modes exist, but you ask for them
by name (InsecureAllowAllCORS, GRPC_INSECURE).
No runtime reflection for dependency injection. No implicit model fetching. No hidden interceptors. Every line of code does what it says.
- HTTP: router, middleware, validation, CSRF, gRPC
- Data: ORM, cache, queues
- Auth: guards, gates, policies
- Messaging: events, command bus, notifications, broadcasting
- Frontend: Inertia.js adapter
- Ops: scheduler, encryption, tracing, storage
- DX: CLI, live reload, test helpers, and string/async/pipeline helpers
Every subsystem is an importable package, usable on its own. See vel.build/docs for the full list.
An in-memory app harness, model factories, database refresh, a fluent HTTP client, and fakes for events and the command bus. Refresh the schema, seed with a factory, drive a route, then chain assertions against the response:
tc := ormtesting.NewTestCase(t, manager)
tc.LazyRefreshDatabase() // migrate once, truncate per test
ormtesting.NewModelFactory[User](manager, newUser).
State("admin").
CreateOne(ctx, nil) // seed test data
velhttp.NewTestClient(t, router).
ActingAs(guard, user).
PostJSON("/signup", map[string]any{"email": "a@b.com"}).
AssertCreated().
AssertJSONPath("user.email", "a@b.com")Status, header, cookie, body, JSON-path, validation, and auth assertions all chain. Testing docs.
Each project builds a ./vel binary for development and code generation.
./vel serve # dev server with live reload
./vel build # compile the production binary
./vel migrate # run migrations (also :fresh, :rollback, :status)
./vel queue:work # process queued jobs
./vel schedule:work # run the scheduler
./vel route:list # list registered routes
./vel cache:clear # flush the cache
./vel key:generate # generate the app encryption key
./vel up / ./vel down # toggle maintenance mode
./vel make:model User # scaffold (model, handler, job, policy, provider, migration, ...)Full reference: vel.build/docs/cli/commands.
Velocity follows semantic versioning. Until
v1.0.0 ships, minor versions may include breaking API changes —
always documented in CHANGELOG.md under the version's
Breaking section.
Arrow is a Velocity-aware MCP server that gives AI agents (Claude Code, Cursor, Codex, and more) the context to write correct Velocity code: app info, database schema, route listing, doc search, log reading, and config inspection, plus auto-generated guidelines and skills matched to your project.
go install github.com/velocitykode/velocity-arrow@latestvelocity-mcp lets you rapidly build your own MCP servers for Velocity applications, exposing tools, resources, and prompts to AI agents.
Velocity is open-source software licensed under the MIT License.