Buffalo — Structure#
Layout pattern#
Framework-specific / Root-package library
Buffalo does not follow the standard Go layout (cmd/internal/pkg). There is no cmd/ directory — the framework itself is the product. The root package (package buffalo) contains the entire public API surface: App, routing, middleware, context, sessions, and handlers. Subsystems are organized as sibling packages at the top level. This is the idiomatic layout for Go libraries that are used by user applications rather than executed directly.
Directory map#
repositories/buffalo/
├── *.go # Root package: App, routing, middleware, context, sessions, handlers
├── binding/ # HTTP request binding (form, JSON, XML, multipart)
│ └── decoders/ # Custom type decoders (time, null types)
├── internal/ # Private utility packages (not exported to consumers)
│ ├── env/ # ENV var loading (.env / godotenv integration)
│ ├── httpx/ # HTTP helper utilities
│ ├── meta/ # App metadata reader (buffalo-app.toml, database.yml detection)
│ ├── nulls/ # Null type helpers
│ ├── templates/ # Embedded HTML templates (error.dev.html, error.prod.html, notfound.prod.html)
│ └── testdata/ # Test fixtures (disk + embedded)
├── mail/ # Email subsystem (SMTP sender, attachment, MIME handling)
├── plugins/ # Plugin discovery and event dispatch
│ ├── plugcmds/ # Plugin command registry (available commands, plug maps)
│ └── plugdeps/ # Plugin dependency metadata (pop integration)
├── render/ # Rendering engine (HTML/plush, JSON, XML, plain, SSE, markdown, download)
├── runtime/ # Build metadata (build.go — version/build info)
├── servers/ # HTTP server implementations (simple, TLS, listener)
└── worker/ # Background job interface and simple in-process workerEntry points#
There are no cmd/ entry points. Buffalo is a library. The framework does not ship a binary — user applications create their own main.go that calls buffalo.New(opts) to obtain an App and then call app.Serve().
The only binary-adjacent artifact is the Docker test image (Dockerfile) which runs go test ./... against the framework source itself.
Package organization#
Internal packages:
internal/env— wrapsgodotenvfor.envfile loading; used byApp.New()at startupinternal/httpx— HTTP utility helpers (content-type detection etc.)internal/meta— readsconfig/buffalo-app.tomlor auto-detectsdatabase.ymlfor plugin contextinternal/nulls— null-safe wrappers for primitive types (used in binding)internal/templates— embedded error page HTML (dev vs. prod error rendering)
Public packages (top-level siblings):
binding— content-type–aware request body binding; dispatches to JSON, form (monoculum/formam), XML, or multipart decodersbinding/decoders— registers customtime.Timeand null-type decodersmail— full SMTP email stack: composer, MIME encoding, attachments, authplugins— plugin discovery viabuffalo-pluginsbinary convention; dispatches CLI events to registered plugin binariesplugins/plugcmds— resolves available plugin commands; caches resultsplugins/plugdeps— pop/database dependency metadata for plugin command decorationrender— unifiedRendererinterface with implementations: HTML (plush), JSON, XML, plain, SSE, download, markdown, JSruntime— exposes build-time version and environment metadataservers—Serverinterface withSimple(plain HTTP) andTLSimplementations; wrapsnet/http.Serverworker—Workerinterface for background jobs;Simpleimplementation runs jobs in goroutines
Layering: The root
buffalopackage is the integration layer. It depends onbinding,render,servers,worker, andpluginsbut these sub-packages are deliberately kept independent of each other (no cross-imports between siblings). This is closer to a hexagonal / ports-and-adapters style: theAppat the centre, withrender,worker,servers, andbindingas exchangeable adapters.
Build system#
- Build tool: None (no
Makefile). Standardgo build/go test. - Key targets:
go test -tags "sqlite integration_test" -cover -race ./... - CI: GitHub Actions using a shared
gobuffalo/.githubreusable workflow (standard-go-test.yml) plusgovulncheckon every push/PR. - Docker: Yes —
Dockerfileis a test runner image (not a production binary image). AlsoDockerfile.buildandDockerfile.slim.buildfor CI matrix variants. Multi-stage is not used; the Dockerfile installs deps and runs tests only.
Notable structural decisions#
Library at root, no cmd/. Buffalo ships as a pure library. This means no cobra CLI wiring in the framework itself — the
spf13/cobradependency is used only in theplugins/subsystem to model plugin commands, not to build a buffalo binary. Users own their ownmain.go.Homestruct in-progress extraction.app.goandhome.goreveal an in-flight refactor (marked#road-to-v1TODOs): routing state (Middleware,ErrorHandlers,router,filepaths) is being moved fromAppinto a newHomestruct to cleanly separate “application lifecycle” from “routing group concerns.” This architectural tension is visible in the code —AppembedsHomeand has temporary bridging fields (root,appSelf,children).Embedded error templates.
internal/templates/holds HTML error pages embedded at compile time (fs.goat root usesembed). The framework ships its own error rendering without runtime file system dependencies — a deliberate distribution convenience.Plugin system as process boundary.
plugins/implements an unusual pattern: plugin discovery works by running external binaries (buffalo-plugins available) and parsing their JSON output. This allows third-party tools to register themselves as buffalo CLI sub-commands without any Go import-level coupling — a process-level plugin architecture rare in Go frameworks.Render as standalone subsystem. The
render/package is self-contained (depends on plush, but not onbuffalo.App) and implements aRendererinterface that routes through different output formats. This clean boundary means the render subsystem could theoretically be used without the rest of buffalo — a good indicator of sound modular design.