Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

golang-uber-fx — Claude Code skill: DI and lifecycle in Go

Skill for uber-go/fx — a dependency injection framework with lifecycle hooks, module system, and graceful shutdown. Useful if your project already uses fx or you're migrating to it for long-running services.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add samber/cc-skills-golang --skill golang-uber-fx -a claude-code
Open on GitHub

What golang-uber-fx does

golang-uber-fx helps you navigate code built on fx.New, fx.Provide, fx.Invoke and lifecycle hooks. The skill provides tools to trace the dependency graph, find constructors, and check types via godig for package reference and gopls for code diagnostics.

Inside the skill: knowledge of how fx differs from raw dig (lifecycle, modules, signal-aware run loop, structured logging), when to use fx.Annotate instead of fx.Out, how value groups and scoped decorators work. The skill helps you write OnStart and OnStop hooks correctly so startup doesn't hang and graceful shutdown respects the timeout.

Requires Go and a working environment. If your project doesn't use fx, this skill won't help; for raw dig without lifecycle, use golang-uber-dig instead.

What it helps with

  • trace the dependency graph and initialization order
  • write lifecycle hooks for OnStart and OnStop
  • set up value groups for handler collections
  • migrate from raw dig to fx while preserving types
  • organize modules with scoped decorators

Example prompts for the agent

  • Help me debug why the server won't start: check the lifecycle hooks in all constructors
  • Refactor this code to use fx.Module with a separate logger per module
  • Where is fx.Annotate used here? Find all calls and explain what they do

How to install golang-uber-fx

1Skills CLI (Vercel)

npx skills add samber/cc-skills-golang --skill golang-uber-fx -a claude-code

2Manually: put the files in place

~/.claude/skills/golang-uber-fx/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/golang-uber-fx/

From the same set32

The whole set →
golang-code-style samber A skill for writing clear Go code: line breaking, variable declarations, control flow, when comments help. Use it when writing or reviewing Go, discussing style, or setting project standards. Claude Code CX Codex Cursor +1 44,000installs golang-error-handling samber Skill for idiomatic Go error handling: wrapping with context, chain inspection, structured logging, and samber/oops integration. Apply when creating, wrapping, inspecting, or logging errors in Go code. Claude Code CX Codex Cursor +1 43,200installs golang-security samber Identifies Go vulnerabilities, models threats with STRIDE and DREAD, and fixes injections, secret leaks, and cryptography flaws. Claude Code CX Codex Cursor +1 42,100installs golang-design-patterns samber This skill guides idiomatic Go design for APIs, resource lifecycles, graceful shutdown, and architecture. Use it when designing or reviewing Go code. Claude Code CX Codex Cursor +1 41,900installs golang-performance samber Guides AI coding agents through profiling, memory allocation cuts, and CPU optimization in Go projects using a strict measurement-first cycle. Claude Code CX Codex Cursor +1 41,800installs golang-concurrency samber The skill sets rules for concurrent Go code: goroutine lifecycle, channels and select, mutexes, errgroup, singleflight, worker pools, and fan-out/fan-in pipelines. Claude Code CX Codex Cursor +1 41,600installs golang-database samber Go database guidelines for database/sql, sqlx, and pgx. Enforces parameterized queries, context passing, and explicit connection pool handling without ORMs. Claude Code CX Codex Cursor +1 40,700installs golang-naming samber A Go naming skill for writing, reviewing, and refactoring code. It covers packages, types, errors, booleans, enums, and tests. Claude Code CX Codex Cursor +1 40,700installs

Similar

iii-core-primitives iii-hq Guides agents on iii engine primitives: functions, triggers, workers, and invocation modes across TypeScript, Python, and Rust. Claude Code CX Codex Cursor +1 4,000installs iii-error-handling iii-hq Skill teaches agents to read iii engine and SDK error codes, tell network failures from access denials, know when it is safe to retry. Use it when calling remote functions from Node, Python, Rust, or browser code. Claude Code CX Codex Cursor +1 4,000installs microservices-patterns Seth Hobson A practical guide to service boundaries, event-driven communication, data ownership, and resilience patterns for distributed systems. Claude Code CX Codex Cursor 13,176installs langchain-architecture Seth Hobson This skill helps design LangChain 1.x and LangGraph applications with agents, memory, state, and tool calls. Use it for multi-step LLM workflows. Claude Code CX Codex Cursor 13,150installs php-pro https://github.com/Jeffallan Enforces PHP 8.3+ standards across Laravel and Symfony projects with strict typing, PHPStan level 9 checks, and automated Pest tests. Claude Code CX Codex Cursor +1 15,500installs protocol-reverse-engineering Dávid Balatoni This skill helps inspect network traffic, map protocol structures, and write protocol documentation. Use it for proprietary protocol analysis or network debugging. Claude Code CX Codex Cursor 12,701installs mcp-builder official anthropics This skill walks through building an MCP server in TypeScript or Python, from reading the protocol spec to writing tests and evaluation questions. Claude Code Claude.ai 130,949installs google-agents-cli-adk-code official Google A reference skill for building ADK agents with tools, callbacks, state, and workflows. Use it when an agent project needs concrete API patterns or code examples. Claude Code CX Codex Cursor +1 511,400installs

Questions about golang-uber-fx

How do I install golang-uber-fx?

Run npx skills add samber/cc-skills-golang --skill golang-uber-fx -a claude-code for Claude Code (for other platforms: replace claude-code with codex, cursor, github-copilot, gemini-cli, or opencode). The skill will be added to ~/.claude/skills/golang-uber-fx/SKILL.md and available in your IDE.

What does golang-uber-fx do?

It helps you work with uber-go/fx code: navigate the DI graph, understand lifecycle hooks, value groups, modules and decorators. Provides access to godig and gopls for package lookup and type diagnostics.

When should I use fx instead of raw dig?

Use fx for long-running services (HTTP, workers, daemons) that need lifecycle hooks, graceful shutdown, and modular composition. For CLIs, libraries, or embedded DI, use raw dig (golang-uber-dig skill).

Source text

SKILL.md · MIT
---
name: golang-uber-fx
description: "Golang application framework using uber-go/fx — fx.New, fx.Provide, fx.Invoke, fx.Module, fx.Lifecycle hooks, fx.Annotate (name/group/As), fx.Decorate, fx.Supply, fx.Replace, fx.WithLogger, and signal-aware Run(). Apply when using or adopting uber-go/fx, when the codebase imports `go.uber.org/fx`, or when wiring services with fx.New. For raw DI without lifecycle, see `samber/cc-skills-golang@golang-uber-dig` skill."
user-invocable: true
license: MIT
compatibility: Designed for Claude Code, Codex or similar harness, and for projects using Golang.
metadata:
  author: samber
  version: "1.2.2"
  openclaw:
    emoji: "🏭"
    homepage: https://github.com/samber/cc-skills-golang
    requires:
      bins:
        - go
    install: []
    skill-library-version: "1.24.0"
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*
paths:
  - "**/*.go"
---

**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:**

- [pkg.go.dev/go.uber.org/fx](https://pkg.go.dev/go.uber.org/fx)
- [uber-go.github.io/fx](https://uber-go.github.io/fx/)
- [github.com/uber-go/fx](https://github.com/uber-go/fx)

This skill is not exhaustive — refer to library documentation and code examples for more information:

- For Go package docs, symbols, versions, importers, and known vulnerabilities, → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`), preferred over Context7 for Go package facts.
- To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See `samber/cc-skills-golang@golang-gopls` skill (`gopls`).
- Context7 remains a fallback for docs not indexed on pkg.go.dev.

```bash
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:

| Concern | dig | fx |
| --- | --- | --- |
| DI container | ✅ `dig.New()` | ✅ (embedded) |
| Lifecycle hooks | ❌ | ✅ `fx.Lifecycle` OnStart/OnStop |
| Module system | ❌ | ✅ `fx.Module` with scoped decorators |
| Signal-aware run loop | ❌ | ✅ `app.Run()` blocks on SIGINT/SIGTERM |
| Structured event logging | ❌ | ✅ `fx.WithLogger` / `fxevent` |
| Startup/shutdown timeout | ❌ | ✅ `fx.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

```go
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

```go
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`.

```go
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):

```go
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.

```go
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:

```go
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:

```go
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.

```go
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](./references/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

| Mistake | Fix |
| --- | --- |
| Long-running work directly in OnStart | Spawn a goroutine inside OnStart; the hook itself must return quickly so dependent hooks can run. |
| `fx.Provide` something that should be `fx.Supply` | Pre-built values (config, secrets) belong in `fx.Supply` — clearer and avoids a no-op constructor. |
| Module decorator leaking to siblings | Decorate inside `fx.Module(...)` — decorators flow only to descendants. A top-level `fx.Decorate` is global. |
| Group order assumed | Groups are unordered. If order matters, provide an ordered slice from one constructor. |
| Constructors with side effects | Side effects belong in OnStart — constructors should be cheap and pure-ish, since they may run concurrently and lazily. |
| Forgotten `fx.Invoke` | Without 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](./references/testing.md).

## Further Reading

- [advanced.md](./references/advanced.md) — Supply/Replace/Decorate, optional deps, custom event logging, manual lifecycle, full Quick Reference
- [recipes.md](./references/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](./references/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>.

© samber · MIT · samber/cc-skills-golang

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor