Plumego: A Deliberate Go Framework for Engineers Who Value Explicitness
Birdor Engineering
Introduction: Why Another Go Framework?
The Go ecosystem does not suffer from a lack of web frameworks. From minimalist routers to batteries-included solutions, developers can choose from a wide spectrum of abstractions. Yet, despite this abundance, many experienced teams eventually encounter a recurring problem:
Their framework either does too little to guide large systems, or too much to stay out of the way.
Plumego exists in the narrow but important space between these extremes.
It is not designed to win popularity contests, nor to optimize for the fastest “Hello World.” Instead, Plumego is built for engineers who care about long-term maintainability, architectural clarity, and explicit control over system behavior.
This article offers a comprehensive, end-to-end introduction to Plumego: its philosophy, its architectural model, its core components, and its intended use cases. The goal is not merely to explain what Plumego does, but why it exists, and when it is the right tool for a team.
The Core Philosophy: Explicit Over Magical
Most modern frameworks optimize for developer convenience by hiding complexity behind convention. While this approach accelerates early development, it often introduces invisible coupling, implicit behavior, and debugging challenges as systems grow.
Plumego makes a different trade-off.
Explicitness as a First-Class Principle
In Plumego:
- Routing is explicit.
- Middleware ordering is explicit.
- Context propagation is explicit.
- Dependency boundaries are explicit.
- Lifecycle ownership is explicit.
Nothing “just happens” because a struct happens to have the right name or tag.
This explicitness is not accidental friction. It is a deliberate design choice grounded in a simple belief:
In production systems, clarity scales better than convenience.
Design Goals of Plumego
Before discussing features, it is important to understand what Plumego is optimized for.
What Plumego Optimizes For
- Long-running backend services
- Medium to large codebases
- Teams with multiple contributors
- Strong separation of concerns
- Predictable runtime behavior
- Observability and traceability
- Evolution over years, not weeks
What Plumego Does Not Optimize For
- Ultra-rapid prototyping
- Code generation heavy workflows
- “Zero-config” applications
- Framework-driven domain modeling
- Tight coupling to ORMs or view engines
Plumego is opinionated, but its opinions favor engineering discipline, not abstraction density.
Architectural Overview
At its core, Plumego provides a thin but structured runtime around the Go standard library.
Rather than reinventing HTTP, concurrency, or networking, Plumego builds on net/http and focuses on composition, lifecycle management, and explicit boundaries.
High-Level Architecture Layers
A typical Plumego service consists of the following conceptual layers:
-
Transport Layer
- HTTP server
- WebSocket handlers
- Webhook endpoints
-
Routing Layer
- Explicit route registration
- Grouped routes
- Method-aware handlers
-
Middleware Layer
- Authentication
- Authorization
- Logging
- Tracing
- Recovery
-
Context Layer
- Request-scoped data
- Trace IDs
- User identity
- Deadlines and cancellation
-
Application Layer
- Use cases
- Business logic orchestration
-
Domain Layer
- Core entities
- Domain services
- Invariants
-
Infrastructure Layer
- Databases
- Caches
- Message queues
- External APIs
Plumego does not enforce this structure, but it naturally encourages it through its APIs and examples.
The Plumego Runtime Model
One of the most distinctive aspects of Plumego is its runtime model.
Explicit Server Lifecycle
In Plumego, you do not “run an app.” You construct a server.
srv := plumego.NewServer(plumego.ServerConfig{
Addr: ":8080",
})
srv.Use(middleware.Recovery())
srv.Use(middleware.Logging())
srv.Route(func(r *plumego.Router) {
r.GET("/health", healthHandler)
})
if err := srv.Start(); err != nil {
log.Fatal(err)
}
This style emphasizes:
- Explicit configuration
- Explicit middleware registration
- Explicit routing
- Explicit startup and shutdown
There is no hidden global state and no implicit bootstrapping.
Routing: Clarity Over Convention
Routing in Plumego is intentionally straightforward.
Explicit Route Registration
Routes are registered via explicit method calls:
r.GET("/users/:id", getUser)
r.POST("/users", createUser)
There is no automatic binding between controllers and URLs, no reflection-based discovery, and no code generation.
This has several benefits:
- Routes are searchable
- Routes are reviewable
- Routes are diff-friendly
- Routes are easy to audit
Route Grouping
Plumego supports grouping for logical clarity:
api := r.Group("/api")
api.Use(authMiddleware)
api.GET("/projects", listProjects)
api.POST("/projects", createProject)
Grouping is explicit and composable, avoiding deeply nested or implicit route trees.
Middleware: Order Is a Feature
In Plumego, middleware is applied in the order it is registered. This is not hidden, abstracted, or normalized.
Why Order Matters
Middleware order directly affects:
- Authentication before authorization
- Logging before or after recovery
- Tracing span lifetimes
- Error handling semantics
Plumego makes this order visible and intentional.
srv.Use(tracing.Middleware())
srv.Use(logging.Middleware())
srv.Use(auth.Middleware())
There is no “magic default stack.” What you see is what runs.
Context Handling: Structured and Predictable
Plumego provides a structured request context abstraction that builds on context.Context.
Request Context Features
- Request-scoped key-value storage
- Strong typing where possible
- Cancellation propagation
- Deadline awareness
- Trace and request ID access
Unlike frameworks that overload context with framework-specific magic, Plumego treats context as a disciplined contract between layers.
Error Handling Philosophy
Error handling is one of the most overlooked aspects of framework design.
Plumego takes a conservative approach.
Errors Are Values
- No panic-driven control flow
- No hidden error swallowing
- No global exception mappers
Handlers return errors explicitly, and error translation is handled via middleware or adapters.
This approach aligns with Go’s philosophy and improves observability and testability.
Observability by Design
Production systems live or die by their observability.
Plumego is designed to integrate cleanly with:
- Structured logging
- Distributed tracing
- Metrics collection
Traceability as a First-Class Concern
Plumego encourages:
- Trace IDs attached at ingress
- Context propagation across layers
- Explicit logging fields
Rather than embedding a specific observability stack, Plumego provides clear integration points.
WebSocket and Real-Time Support
While HTTP remains the dominant protocol, many systems require real-time communication.
Plumego treats WebSocket support as a first-class transport, not an afterthought.
- Explicit upgrade handling
- Context-aware connections
- Clear lifecycle hooks
- Predictable shutdown behavior
This makes Plumego suitable for dashboards, collaborative tools, and game backends.
Pub-Sub and In-Process Messaging
Plumego includes a lightweight in-process pub-sub mechanism designed for:
- Domain events
- Internal notifications
- Decoupled module communication
This is not intended to replace Kafka or Redis, but to provide a clean internal signaling mechanism.
Security: Explicit and Auditable
Security features in Plumego are intentionally minimal but composable.
Authentication and Authorization
- JWT support via middleware
- Explicit token validation
- No hidden session state
- Clear separation between authn and authz
Why Minimalism Matters
Security systems are easier to audit when they are explicit. Plumego avoids “secure by magic” patterns in favor of visible, testable flows.
Dependency Management and Inversion
Plumego does not include a dependency injection container.
This is intentional.
Why No Built-In DI?
- Go already has constructors
- Explicit wiring improves readability
- Reflection-based DI hides dependencies
- Compile-time safety matters
Plumego encourages manual wiring at application boundaries, making dependencies obvious and refactor-friendly.
Testing Philosophy
Plumego is designed to be easy to test without framework gymnastics.
Testability Advantages
- Handlers are plain functions
- Context can be constructed manually
- No global state
- No hidden singletons
This results in tests that are:
- Fast
- Deterministic
- Easy to reason about
Comparison with Other Go Frameworks
It is useful to position Plumego relative to common alternatives.
Compared to Minimal Routers
Plumego provides more structure and lifecycle management while retaining explicit control.
Compared to Full-Stack Frameworks
Plumego avoids:
- ORM lock-in
- Template engines
- Code generation
- Heavy conventions
It focuses strictly on service architecture, not application scaffolding.
When Plumego Is a Good Fit
Plumego is well-suited for:
- Internal platforms
- SaaS backends
- Developer tools
- Game servers
- Infrastructure APIs
- Long-lived services with evolving requirements
When You Should Not Use Plumego
Plumego is likely not the right choice if:
- You need a prototype in a day
- You prefer convention over configuration
- Your team is new to Go
- You expect the framework to make architectural decisions for you
Plumego assumes engineering maturity.
The Birdor Perspective
Plumego is developed and used within the broader Birdor engineering ecosystem. It reflects Birdor’s core values:
- Calm engineering
- Explicit systems
- Long-term thinking
- Respect for the Go standard library
Plumego is not a product framework. It is an engineering framework.
Roadmap and Future Direction
Plumego’s roadmap is intentionally conservative.
Future work focuses on:
- Refining APIs
- Improving documentation
- Strengthening examples
- Enhancing observability integrations
There is no plan to turn Plumego into a monolith or a “do everything” platform.
Conclusion: A Framework with Restraint
Plumego is not trying to be everything to everyone.
It is a framework for engineers who:
- Prefer clarity over cleverness
- Value explicit control
- Build systems meant to last
- Believe that architecture is a responsibility, not a feature
If that description resonates with you, Plumego may be the framework you have been looking for.
Plumego is opinionated, but its strongest opinion is this:
Good software is built deliberately.