v1.6.2MITgo 1.18+github.com/xgodev/boost

Enterprise Go services.
Built fast.

Boot, config, logs, 58 factories, middleware, health and code generation in one framework. You write the business logic.

$go get github.com/xgodev/boost
Get started
58factories 46libraries 107plugins 221releases since 2024

A complete service: one route, a service, a repository and two datastores. The generated files and the run are the real output.

github.com/acme/shop
internal/
app/
api/rest/
handler/stock/reserver/
pkg/
domain/
service/stock/reserver/
local/
repository/stock/
datastore/stock/
memory/
mongodb/
you writeinternal/app/api/rest/handler/stock/reserver/handler.go
// Package reserver serves POST /stock/:sku/reserve.
package reserver

import (
	"net/http"

	"github.com/acme/shop/internal/pkg/domain/service/stock/reserver"
	"github.com/labstack/echo/v4"
)

// Handler reserves one unit of an item.
type Handler struct {
	svc reserver.Service
}

// New provides the handler to the generated rest door.
// @Provide(index=0)
func New(svc reserver.Service) *Handler {
	return &Handler{svc: svc}
}

// Handle reserves one unit of the sku in the path.
// @REST(method=POST, path=/stock/:sku/reserve)
func (h *Handler) Handle(c echo.Context) error {
	if err := h.svc.Reserve(c.Request().Context(), c.Param("sku")); err != nil {
		return err
	}
	return c.NoContent(http.StatusNoContent)
}
github.com/xgodev/boost · bootstrap

One boot. Everything ready after it.

boost.Start() runs first. When it returns, config is loaded and the logger is set, so every factory reads its own keys and logs the same way.

  1. 01boost.Start()Reads flags, env vars and config files.
  2. 02configEvery key declared once, with a default and a description.
  3. 03logzap, zerolog or logrus behind one wrapper.
  4. 04factoryOne constructor per component, plugins applied.
  5. 05fxGenerated modules wire the dependency graph.
  6. 06serveREST, gRPC, MCP or an event function.

One key, three ways to set it

Keys live under boost.factory.<component>.* and reach the app from wherever you deploy.

keyboost.factory.zap.console.level
envBOOST_FACTORY_ZAP_CONSOLE_LEVEL=DEBUG
flag--boost.factory.zap.console.level=DEBUG
// cmd/api/main.go, written by go generate
func main() {
	boost.Start()

	fxfact.NewApp(app.Modules()...).Run()
}
packages

Every piece has one job.

Factories build, wrappers abstract, generators remove the wiring. Use one package or all of them.

factory/contrib/labstack/echo/v4

Factories

One constructor per component. You never instantiate the SDK by hand: the factory reads its config keys, applies the plugins you list and returns the ready client.

srv, _ := echo.NewServer(ctx,
	cors.Register,
	requestid.Register,
	gzip.Register,
	log.Register,
	health.Register,
)
srv.GET("/stock/:sku", Get)
srv.Serve(ctx)
58factories
46upstream libraries
107plugins
…/echo/v4/plugins

Plugins

Behaviour you opt into per factory, applied in the order you list it.

corsrequestidgziploghealthrecoverbodylimitprometheusoteldatadogswaggosemaphore
wrapper/{log,config,cache,publisher}

Wrappers

Swap zap for zerolog by changing one line in main. App code only ever calls the wrapper.

log.FromContext(ctx).
	Infof("reserved %s", sku)
extra/middleware

Middleware

Wraps any call in log, cache, hystrix, datadog, prometheus or fallback. With @Middleware the decorator is generated and the method body stays clean.

log
prometheus
hystrix
Service.Reserve()
@Middleware(log, prometheus, hystrix) · first is outermost
inject

Inject

@Provide, @Inject and @Invoke become one fx module per function and a root Module().

@Defaultmemory.New | mongodb.Newstock.Repository
↓
@Middlewarelocal.New(repo)reserver.Service
↓
@Providereserver.New(svc)*Handler
↓
@RESTHandler.HandlePOST /stock/:sku/reserve
  • cycles and missing providers fail at go generate, not in production
  • two providers of the same value are rejected
annotation

Annotation

Reads // @Name(key=value) from doc comments into typed structs. Every generator here is built on it.

var r struct {
	Path string `attr:"path"`
}
ann.Decode(&r)
bootstrap/function

Functions

One event handler, six transports. Change the adapter in config; the handler stays the same.

func(ctx, in cloudevents.Event)
	(*cloudevents.Event, error)
factory/contrib/modelcontextprotocol/go-sdk/v1/{server,client}

MCP

Your use cases become tools that agents call over MCP, and your service calls other MCP servers. Server and client are factories like the rest: config keys, plugins, and the server runs beside echo and gRPC. Mark a handler with @MCP and the builder registers it as a tool.

server · HTTPserver · STDIOclient · HTTPclient · COMMANDlogotel
srv, _ := server.NewServer(ctx, mcplog.Register, otel.Register)
mcp.AddTool(srv.Instance(), &mcp.Tool{
	Name:        "reserve",
	Description: "holds items for an order",
}, reserve)
srv.Serve(ctx)
builder · inject · annotation

From annotation to binary in two commands.

You write handlers, services and annotations. Everything that repeats between services is generated, checked and rewritten on every run.

  1. Annotate

    Mark constructors with @Provide, handlers with a door, services with @Middleware, the default implementation with @Default, options with @Config.

  2. Generate

    Inject and builder run in one pass. A broken graph stops here and leaves your output untouched.

    go generate ./...
  3. Run

    Each app gets its own main, with the servers and plugins it declared.

    go run ./cmd/api
generatedoutputrewritten on every run
cmd/api/main.go                // boost.Start(), then app api
gen/
├── builder/
│   ├── api/
│   │   ├── modules.go         // the doors of app api
│   │   └── rest_module.go     // @REST POST /stock/:sku/reserve
│   └── middleware/…/local/
│       └── new_middleware.go  // @Middleware(log, prometheus)
├── implementation/…/stock/
│   └── repository_implementation.go
│                              // @Default: memory | mongodb
├── internal/
│   ├── app/…                  // one module per @Provide,
│   └── pkg/…                  // @Config: same tree as yours
└── module.go                  // every inject module
backward compatibility

Upgrade boost.
Keep your code.

A minor release never asks you to rewrite a service. That is a rule of the project, enforced on every pull request.

Public API is a contract

A component's public API does not break without a major version bump and a written reason. Any observable change ships with a test first.

SDK majors live side by side

Factory paths carry the upstream major. Moving to a new SDK is an import you choose, not a forced migration.

factory/contrib/go.mongodb.org/mongo-driver/v1   // keeps working
factory/contrib/go.mongodb.org/mongo-driver/v2   // new SDK major

A gate that only moves forward

Every PR is compared to develop: format, lint, build and tests can stay the same or get better, never worse.

go.modyour service
 module github.com/acme/shop

 require (
-	github.com/xgodev/boost v1.1.1+	github.com/xgodev/boost v1.6.2 )

$ go build ./... && go test ./...
ok  github.com/acme/shop/...
1 line changed in go.mod0 lines changed in your code
2024-07v1.1.0v1.1.1v1.6.2
factory/contrib

There's a factory for that.

58 factories over the 46 libraries your services already run on. Each one arrives configured, with plugins for traces, metrics and health checks, so your team writes the business logic, not the plumbing.

Also: chi · Fiber · Resty · fasthttp · drpc · HTTP/2 · kafka-go · Goka · Go CDK Pub/Sub · BigCache · FreeCache · BuntDB · memdb · Bigtable · FTP · Azure Blob · Hystrix · zap · zerolog · logrus · fx · Cobra · ants.

All 46 libraries, with the upstream major each factory wraps

Web, RPC & MCP

Messaging

Data

Cache

Observability

Logging & platform

Why a factory, not just the SDK

Any SDK connects in five lines. Running it in a company takes the rest: config per environment, auth, checks, logs, metrics, traces. That part is the same in every service, so boost writes it once.

boost.factory.<name>.*

Configured, not coded

Every option is a config key with a default, read from file or environment: boost.factory.mongo.uri is BOOST_FACTORY_MONGO_URI. One binary for every environment.

what you skip

The plumbing comes built

Defaults, auth, connect and ping, structured logs through wrapper/log. What a platform team rewrites for every SDK in every service is already there.

plugins/

78 plugins to plug in

OpenTelemetry, Prometheus, Datadog, health checks, retry, request id, CORS, gzip. Pass the plugin to the factory; switch it off with a key.

by handMongoDB, in every service
  • Read URI, user and password from the environment, with defaults
  • Build the client options and the authentication
  • Connect and ping before taking traffic
  • Trace every command with OpenTelemetry
  • Count commands and errors in Prometheus
  • Register a health check
  • Log commands when you need to debug
  • Then again for Kafka, Redis, gRPC, the HTTP client…
with boostfactory/contrib/go.mongodb.org/mongo-driver/v2
conn, err := mongo.NewConn(ctx,
	mongootel.Register,   // traces
	mongoprom.Register,   // metrics
	mongohealth.Register, // health check
)
$ export BOOST_FACTORY_MONGO_URI=mongodb://db:27017/shop
$ export BOOST_FACTORY_MONGO_AUTH_USERNAME=shop
$ export BOOST_FACTORY_MONGO_PLUGINS_PROMETHEUS_ENABLED=false
Same shape for every factory: New…(ctx, plugins...) and keys under boost.factory.<name>.
claude-plugin@xgodev

Coding agents that follow the rules.

The plugin teaches Claude Code boost's Iron Laws and the project layout, and runs the comparative quality gate before every push.

>/plugin marketplace add xgodev/claude-plugin
>/plugin install claude-plugin@xgodev
  1. boost.Start() firstConfig and log exist only after it.
  2. Log only through wrapper/loglog.FromContext(ctx), never a third-party logger in app code.
  3. Config only through wrapper/configNo os.Getenv; keys under boost.factory.<x>.*.
  4. One factory per componentNever instantiate the upstream SDK directly.
  5. Backward compatiblePublic API breaks only with a major bump and a reason.
go.mod

Start with one line.

$go get github.com/xgodev/boost
See the examples Star on GitHub