DataDog/datadog-agent
Components framework
Active contributors: David Ortiz, Pierre Gimalac, Gabriel Dos Santos
Purpose
comp/ is the Datadog Agent's component framework: a structured way to break the codebase into small, testable units with explicit dependencies. It is built on top of go.uber.org/fx.
In 2026 the framework hosts roughly 48 top-level bundles and many hundreds of components. New code is expected to live in comp/. Older pkg/ code is being incrementally migrated.
Why it exists
Before the component framework, most Agent code lived in pkg/ and used global state (singletons, init() functions, package-level variables). That made the system hard to test in isolation and made the build dependencies non-obvious.
The framework solves this by:
- Replacing globals with interfaces that are injected via Fx.
- Making lifecycle explicit — every component has an
OnStart/OnStophook. - Making bundles the unit of composition: a binary picks the bundles it wants, and the right components fall out automatically.
- Standardizing mocks for tests.
Layout
A canonical component:
comp/<bundle>/<component>/
├── def/ # Component interface (no implementation)
│ └── component.go # The exported `type Component interface { ... }`
├── impl/ # Production implementation
│ └── component.go
├── fx/ # Fx options that wire impl + interface together
│ └── fx.go
└── mock/ # Mock implementation for tests
└── mock.goA bundle (comp/<bundle>/bundle.go) lists the components it owns and exposes a single fx.Option that downstream code imports.
comp/README.md is generated from package docs (dda inv collector.generate) and lists every component with a one-line description. It is the fastest way to find what already exists.
Wiring a binary
Binaries assemble their bundle list under cmd/<binary>/subcommands/run/. Example pattern:
return fxutil.Run(
fx.Supply(...),
core.Bundle(...),
aggregator.Bundle(...),
forwarder.Bundle(...),
dogstatsd.Bundle(...),
logsbundle.Bundle(...),
// ...
fx.Invoke(func(...components...) { /* start work */ }),
)The Fx graph computes the topological order of OnStart calls, runs them, then waits for shutdown signals. On shutdown it invokes OnStop in reverse order.
Key bundles
| Bundle | Lives in | What it provides |
|---|---|---|
comp/core |
Bundle of fundamentals | config, log, secrets, hostname, tagger, workloadmeta, autodiscovery, status, flare, healthprobe, IPC, gohai, agent telemetry |
comp/aggregator |
comp/aggregator/ |
Demultiplexer |
comp/collector |
comp/collector/ |
Collector (the check runtime) |
comp/forwarder |
comp/forwarder/ |
Default forwarder, event-platform forwarder, orchestrator forwarder |
comp/serializer |
comp/serializer/ |
Metrics and logs serializers |
comp/dogstatsd |
comp/dogstatsd/ |
Server, listeners, mapper, replay |
comp/logs |
comp/logs/ |
Logs agent, audit, integration support |
comp/trace |
comp/trace/ |
Embedded trace agent |
comp/metadata |
comp/metadata/ |
Inventory and host metadata payloads |
comp/checks |
comp/checks/ |
Component-based checks (Windows event log, …) |
comp/api |
comp/api/ |
HTTP API and gRPC server |
comp/otelcol |
comp/otelcol/ |
OTel Collector integration |
comp/snmptraps, comp/netflow, comp/networkpath, comp/ndmtmp |
Various | Network device monitoring components |
comp/haagent |
comp/haagent/ |
High-availability Agent logic |
comp/updater |
comp/updater/ |
Agent self-update support |
comp/process |
comp/process/ |
Process Agent core |
Conventions
- Interfaces in
def/; one component per directory. - Fx options in
fx/<name>fx/. Convention: a package named<name>fxso the import looks likeimport autoscalingfx "..."and the symbol isautoscalingfx.Module(). - Mock implementations in
mock/; tests import the mock instead of the impl. - Lifecycle hooks via
compdef.Lifecycle— register OnStart/OnStop in the constructor. - Do not panic in constructors. Return errors instead so Fx can report a clean failure.
- Avoid global variables; use Fx-injected dependencies. The migration is incremental, but new code is held to this standard.
Variants
For the same interface, multiple impls coexist:
impl/— production.mock/— test mock.- Sometimes
impl-none/orimpl-noop/for no-op variants used in stripped flavors (serverless, IoT). - Sometimes
fx-noop/orfx-mock/for the corresponding Fx wiring.
For example, comp/forwarder/defaultforwarder/ has full and no-op variants — the IoT Agent uses the no-op when it doesn't need to forward anything.
How a new component is added
- Generate the scaffold via
.claude/skills/create-component/(or by copying an existing minimal component). - Define the interface in
comp/<bundle>/<component>/def/component.go. - Write the production implementation in
impl/. - Provide an
fx/package that constructs the impl and registers it with Fx. - Write a
mock/package; add it to.mockery.yamlif the mock is generated. - Add the new component to its bundle's
bundle.go. - Reference the component from the binaries that need it.
- Regenerate
comp/README.mdviadda inv collector.generate.
The .claude/skills/create-component/ skill walks through this in detail.
Migration patterns
When migrating from pkg/ to comp/:
- Start with an interface that mirrors the existing public API of the
pkg/package. - Implement the component as a thin wrapper that calls into the existing
pkg/code. - Switch all callers to use the component (via Fx injection).
- Move logic from
pkg/intoimpl/. - Delete the
pkg/package.
Most migrations stop at step 3 and 4 — they leave pkg/ packages alive as long as they're useful.
Key abstractions
| Type / package | Location | Description |
|---|---|---|
fx.Option |
go.uber.org/fx | The unit of composition |
fxutil |
pkg/util/fxutil/ |
Datadog's Fx helpers (test runners, supply helpers) |
compdef.Lifecycle |
comp/def/ |
Lifecycle hook abstraction |
bundle.Bundle() |
per-bundle | The bundle's fx.Option |
Entry points for modification
- Adding a component: see "How a new component is added" above.
- Adding a new bundle: create
comp/<bundle>/bundle.goand reference it from the binaries that need it. - Changing component lifecycle: be very cautious — most components have
Start/Stopsemantics tested by other components. Update tests for both.
Related pages
- Tooling —
dda inv components.create. - Patterns and conventions — coding rules for new components.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.