Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
samber avatar

Golang Uber Fx

  • 31.6k installs
  • 2.8k repo stars
  • Updated July 27, 2026
  • samber/cc-skills-golang

uber-go/fx is a Go application framework for DI, lifecycle management, and modular service composition.

About

uber-go/fx is a Go application framework that combines dependency injection with lifecycle management and signal handling. It uses reflection-based wiring like dig but adds OnStart/OnStop hooks, module composition, and a blocking run loop for services. Developers use it when building long-running services like HTTP servers and workers that need coordinated startup and shutdown.

  • Lifecycle hooks with OnStart/OnStop for graceful shutdown
  • Module system for composable service wiring
  • Signal-aware run loop that blocks on SIGINT/SIGTERM

Golang Uber Fx by the numbers

  • 31,582 all-time installs (skills.sh)
  • +412 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Ranked #32 of 4,386 Backend & APIs skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

golang-uber-fx capabilities & compatibility

Capabilities
di wiring · lifecycle management · module composition
Platforms
macOS · Windows · Linux
Runs
Runs locally
Pricing
Free
npx skills add https://github.com/samber/cc-skills-golang --skill golang-uber-fx

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs31.6k
repo stars2.8k
Security audit3 / 3 scanners passed
Last updatedJuly 27, 2026
Repositorysamber/cc-skills-golang

How do you wire Go services with Uber Fx?

Wire and manage long-running Go services with dependency injection, lifecycle hooks, and graceful shutdown.

Who is it for?

Long-running services needing DI, lifecycle hooks, and coordinated startup/shutdown

Skip if: CLI tools or simple scripts where DI overhead is unnecessary

When should I use this skill?

Building HTTP services, workers, or daemons with complex dependency graphs

What you get

Fx application modules with providers, invokes, lifecycle hooks, and signal-aware Run() startup.

  • Fx application bootstrap code
  • Modular fx.Module provider sets

By the numbers

  • Skill version 1.1.0 from samber/cc-skills-golang

Files

SKILL.mdMarkdownGitHub ↗

Persona: You are a Go architect building a long-running service with fx. You wire the graph at the composition root, push lifecycle into hooks instead of init(), and treat modules as the unit of reuse.

Using uber-go/fx for Application Wiring in Go

Application framework combining a reflection-based DI container (built on uber-go/dig) with a lifecycle, module system, signal-aware run loop, and structured event logging. For long-running services where boot order, graceful shutdown, and modular composition matter.

Official Resources:

This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform. For Go package docs, versions, symbols, and known vulnerabilities, → See samber/cc-skills-golang@golang-pkg-go-dev skill.

go get go.uber.org/fx

fx vs. dig

fx is built on top of dig and shares the same reflection-based container engine. The DI primitives (Provide, Invoke, In/Out structs, named values, value groups) are identical — fx.In/fx.Out are re-exports of dig.In/dig.Out.

What fx adds on top:

Concerndigfx
DI containerdig.New()✅ (embedded)
Lifecycle hooksfx.Lifecycle OnStart/OnStop
Module systemfx.Module with scoped decorators
Signal-aware run loopapp.Run() blocks on SIGINT/SIGTERM
Structured event loggingfx.WithLogger / fxevent
Startup/shutdown timeoutfx.StartTimeout / fx.StopTimeout

Choose fx for long-running services (HTTP servers, workers, daemons) — lifecycle and signal handling are mandatory there, and modules make large service graphs manageable.

Choose raw dig when you need wiring without a framework: CLI tools, libraries that expose a container to callers, test harnesses, or embedding DI into an existing app that manages its own lifecycle. See samber/cc-skills-golang@golang-uber-dig skill.

The Application

import "go.uber.org/fx"

app := fx.New(
    fx.Provide(NewLogger, NewDatabase, NewServer),
    fx.Invoke(RegisterRoutes),
)
app.Run() // blocks until SIGINT/SIGTERM, then runs OnStop hooks

Boot stages: fx.New validates types (constructors do not run); app.Start(ctx) runs each fx.Invoke and fires OnStart hooks in topological order; main blocks on app.Done(); app.Stop(ctx) fires OnStop hooks in reverse order. Default timeout is 15 seconds — override with fx.StartTimeout / fx.StopTimeout.

Provide and Invoke

fx.New(
    fx.Provide(NewLogger, NewDatabase, NewServer),  // lazy
    fx.Invoke(RegisterRoutes, StartMetricsExporter), // always run during Start
)

fx.Provide registers constructors; fx.Invoke is the trigger — without an Invoke (directly or transitively) referencing a type, its constructor never runs.

Lifecycle Hooks

Inject fx.Lifecycle and append hooks. Constructors should return quickly; long-running work belongs in OnStart.

func NewHTTPServer(lc fx.Lifecycle, log *zap.Logger, cfg *Config) *http.Server {
    srv := &http.Server{Addr: cfg.Addr}

    lc.Append(fx.Hook{
        OnStart: func(ctx context.Context) error {
            ln, err := net.Listen("tcp", srv.Addr)
            if err != nil { return err }
            go srv.Serve(ln)         // blocking work in a goroutine
            return nil
        },
        OnStop: func(ctx context.Context) error {
            return srv.Shutdown(ctx)
        },
    })
    return srv
}

Both callbacks receive a context bounded by StartTimeout/StopTimeout — respect cancellation. OnStart must return quickly — spawn a goroutine for blocking work; otherwise startup hangs and dependent hooks never fire.

fx.StartHook / fx.StopHook / fx.StartStopHook adapt simpler signatures (no context, no error, or both):

lc.Append(fx.StartStopHook(srv.Start, srv.Stop))   // matched pair

Parameter and Result Objects

fx re-exports dig's dig.In / dig.Out as fx.In / fx.Out. Use them when a constructor has 4+ dependencies, or when you need name/group/optional tags.

type ServerParams struct {
    fx.In

    Logger *zap.Logger
    DB     *sql.DB
    Cache  *redis.Client     `optional:"true"`
    Routes []http.Handler    `group:"routes"`
}

func NewServer(p ServerParams) *Server { /* ... */ }

fx.Annotate

fx.Annotate wraps a constructor to add tags or interface bindings without a fx.Out struct. Prefer it for ergonomic name/group/As bindings:

fx.Provide(
    fx.Annotate(NewPrimaryDB, fx.ResultTags(`name:"primary"`)),
    fx.Annotate(NewPostgresDB, fx.As(new(Database))),    // expose interface
    fx.Annotate(NewUserHandler,
        fx.As(new(http.Handler)),
        fx.ResultTags(`group:"routes"`),
    ),
)

Value Groups

Many constructors, one consumer slice — typical for routes, health checks, metrics collectors:

type RouteResult struct {
    fx.Out
    Handler http.Handler `group:"routes"`
}

type ServerParams struct {
    fx.In
    Routes []http.Handler `group:"routes"`
}

Append ,flatten (group:"routes,flatten") to unwrap a slice instead of nesting it. Order is not guaranteed — provide an explicit ordered slice when sequence matters.

fx.Module

fx.Module groups providers, invokes, and decorators under a name. Modules scope decorators to themselves and their children — a logger renamed in fx.Module("db", ...) only appears renamed for code inside that module.

var DatabaseModule = fx.Module("database",
    fx.Provide(NewConnection, NewUserRepository),
    fx.Decorate(func(log *zap.Logger) *zap.Logger {
        return log.Named("db")
    }),
)

func main() {
    fx.New(
        fx.Provide(NewConfig, NewLogger),
        DatabaseModule,
        HTTPModule,
    ).Run()
}

Treat each module as a small library that can be lifted into another app — its public surface is the types it Provides.

For fx.Supply/fx.Replace/fx.Decorate, optional deps, custom logging, manual lifecycle, and Quick Reference, see advanced.md.

Best Practices

1. Keep main() thin — providers, modules, and a single Run(). Push real work into modules so each can be tested in isolation. 2. Use lifecycle hooks instead of init() or goroutines launched from constructors — Start/Stop ordering depends on graph topology, but init() goroutines do not, which leads to races and leaks. 3. OnStart must return promptly — long work goes in a goroutine inside the hook. A blocking OnStart hangs the rest of the boot. 4. Respect ctx.Done() in hooks — a hook that ignores cancellation is reported as a timeout failure but its goroutine continues, leaking resources. 5. Group by module, not by layer — a module owns the providers, lifecycle, and decorators for one concern (HTTP, DB, metrics). 6. Use fx.Annotate for tags rather than wrapping a constructor in an fx.Out struct — keeps the constructor reusable outside fx. 7. Replace fx.Provide with fx.Supply for pre-built values (config, command-line flags). Shorter, signals intent. 8. Validate the graph in CI by booting under fx.New(...).Err() — catches missing providers and cycles before deploy.

Common Mistakes

MistakeFix
Long-running work directly in OnStartSpawn a goroutine inside OnStart; the hook itself must return quickly so dependent hooks can run.
fx.Provide something that should be fx.SupplyPre-built values (config, secrets) belong in fx.Supply — clearer and avoids a no-op constructor.
Module decorator leaking to siblingsDecorate inside fx.Module(...) — decorators flow only to descendants. A top-level fx.Decorate is global.
Group order assumedGroups are unordered. If order matters, provide an ordered slice from one constructor.
Constructors with side effectsSide effects belong in OnStart — constructors should be cheap and pure-ish, since they may run concurrently and lazily.
Forgotten fx.InvokeWithout an Invoke (or downstream consumer), constructors never run. Add at least one Invoke per app.

Testing

Use go.uber.org/fx/fxtest to integrate fx with *testing.T (failures call t.Fatal, RequireStop registers as t.Cleanup). fx.Populate(&target) pulls values out of the graph; fx.Replace swaps real dependencies for fakes. Full patterns in testing.md.

Further Reading

  • advanced.md — Supply/Replace/Decorate, optional deps, custom event logging, manual lifecycle, full Quick Reference
  • recipes.md — full HTTP service with database/metrics, background workers with graceful drain, multiple impls of the same interface, manual lifecycle for CLI embedding
  • testing.md — fxtest patterns, fx.Replace, fx.Populate, isolated lifecycle tests, CI graph validation

Cross-References

  • → See samber/cc-skills-golang@golang-uber-dig skill for the underlying container, dig.In/dig.Out, and DI without lifecycle
  • → See samber/cc-skills-golang@golang-dependency-injection skill for DI concepts and library comparison
  • → See samber/cc-skills-golang@golang-samber-do skill for a generics-based alternative without reflection
  • → See samber/cc-skills-golang@golang-google-wire skill for compile-time DI (no runtime container)
  • → See samber/cc-skills-golang@golang-structs-interfaces skill for interface design patterns
  • → See samber/cc-skills-golang@golang-context skill for context propagation in OnStart/OnStop hooks
  • → See samber/cc-skills-golang@golang-testing skill for general testing patterns

If you encounter a bug or unexpected behavior in uber-go/fx, open an issue at <https://github.com/uber-go/fx/issues>.

Related skills

FAQ

What Uber Fx APIs does golang-uber-fx cover?

golang-uber-fx v1.1.0 covers fx.New, fx.Provide, fx.Invoke, fx.Module, fx.Lifecycle hooks, fx.Annotate, fx.Decorate, fx.Supply, fx.Replace, fx.WithLogger, and signal-aware Run() for go.uber.org/fx service wiring.

When should developers pick golang-uber-fx over golang-uber-dig?

Developers should pick golang-uber-fx when they need uber-go/fx lifecycle management, modular fx.Module composition, and graceful startup/shutdown. golang-uber-dig covers raw dig DI without Fx lifecycle orchestration.

Is Golang Uber Fx safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Backend & APIsbackenddevops

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.