v0.6.0 · MIT

Lead with a struct.
tanGO does the footwork.

tanGO is a small, explicit web framework for Go. Plain structs and interfaces, named routes, typed migrations and a server-rendered admin. Scaffolding writes plain Go you own, and there's no hidden configuration.

Start the tutorial
$ go get github.com/angvp/tango
Two gopher mascots dancing tango, one in a black suit and fedora, one in a flowing blue dress

Hello, tanGO

A project that runs, and an app you register by hand.

Apps plug in through public contracts. Scaffolding writes plain Go you own. Nothing is generated at runtime, and boot never scans your filesystem.

apps/greetings/app.go
func (App) Register(registry *tango.Registry) error {
	return registry.Routes().Include("/greetings/", tango.URLs{
		tango.Path("GET", "/{name}/", hello, tango.Name("hello")),
	})
}

func hello(ctx *tango.Context) error {
	name := ctx.Param("name")
	return ctx.JSON(200, map[string]string{
		"message": "Hello, " + name + "!",
	})
}

// main.go: installing the app is one line you write
config.InstalledApps = []tango.App{
	admin.New(store),
	greetings.App{},
}
terminal
$ tango newproject shop
$ cd shop
$ go run .
listening on :8000

# open http://localhost:8000/admin/ in a browser

Where do I start?

Pick what you're building. Each one has a runnable example.

Or follow the step-by-step tutorial, which builds one app from an empty directory to a deployment.

What you get

Batteries included, and every one of them is visible.

  • Explicit lifecycle

    Config, App, Registry. Nothing boots implicitly, and a graceful shutdown you wire in two lines of main.

  • Named routes

    A URL dispatcher with reverse lookup. It's built on chi, but chi never shows up in your imports.

  • Plain-struct models

    A handful of tags: tango:"pk", unique, index, fk=Other. That's the whole grammar.

  • SQLite & PostgreSQL

    A minimal db.Store for CRUD and raw SQL, with foreign keys, validation and cascade delete. One TANGO_DB_DSN picks the database.

  • Typed Go migrations

    makemigrations, migrate, migrate down. Migrations are generated Go, not a separate schema DSL.

  • HTML admin

    List, create, edit, delete, search and sort behind a session login, with CSRF protection and rate-limited logins.

  • Auth, with reset and verification

    An optional accounts app for cookie sessions, password reset and email verification, or stateless HS256 JWTs through auth/jwt.

  • Realtime rooms

    A WebSocket Hub with rooms, reconnect windows and backpressure, wired into graceful shutdown.

  • Jobs & observability

    Background jobs and scheduling, structured HTTP logging, request IDs, and a shared metrics recorder.

  • Production defaults

    Scaffolded projects read PORT, cap request bodies, time out slow headers and log unmatched requests.

If writing normal Go is simpler than invoking tanGO, write normal Go.

The rule of thumb behind every design decision
  • Prefer Go primitives before replacing them.
  • Prefer explicit structure over convention magic.
  • Treat JSON and API-only apps as first-class. HTML is optional.
  • The admin is a normal app, not a privileged subsystem.
  • No custom template language.
  • Third-party internals stay behind tanGO's abstractions.

Dogfooding

This website is a tanGO app.

Named routes, html/template views and embedded static assets. The docs and examples you browse here are rendered, when the site starts, from the tanGO release it's built against, so they always match that release's code.

site/app.go
routes.Include("/docs/", tango.URLs{
	tango.Path("GET", "/", a.docsIndex, tango.Name("index")),
	tango.Path("GET", "/{slug}/", a.rootDoc, tango.Name("page")),
	tango.Path("GET", "/{section}/{slug}/", a.sectionDoc, tango.Name("doc")),
})

// in a template: {{url "docs:page" "slug" "limitations"}}

Know before you choose

  • It is v0.x. tanGO is at v0.6.0. Patch releases never break its public API; before v1.0, a minor release may, but only after a deprecation window (see versioning and compatibility).
  • State is single-process and in-memory. Realtime rooms, rate limiting and the mail outbox do not coordinate across server instances. What that means for more than one instance.
  • The admin is for trusted internal use, not a public-facing panel. The ORM is minimal foundations, not a full ORM.

The limitations list the rest. Read them before you depend on tanGO for anything beyond experimentation.

Read the limitations