Traefik — Structure#

Layout pattern#

Standard Go Layout (cmd/pkg), extended with top-level integration/ and webui/

Traefik follows the broadly-adopted cmd/ + pkg/ layout. There is no internal/ at the root application level — all application packages live under pkg/ and are technically importable (though the project is self-contained). A small cmd/internal/gen/ exists only for the code-generation tool. The project adds non-standard top-level directories for integration testing (integration/) and the Vue.js dashboard (webui/), which is compiled separately and embedded into the binary.

Directory map#

traefik/
├── cmd/                          # CLI entry points and sub-commands
│   ├── configuration.go          # Root TraefikCmdConfiguration struct (wraps static.Configuration)
│   ├── traefik/                  # Main binary: initialization, wiring, signal handling
│   │   ├── traefik.go            # main() + setupServer() + provider/metrics/plugin bootstrap
│   │   ├── logger.go             # Logger setup
│   │   └── plugins.go            # Plugin builder initialization
│   ├── healthcheck/              # `traefik healthcheck` sub-command implementation
│   ├── version/                  # `traefik version` sub-command implementation
│   └── internal/gen/             # Internal code generator (generates config docs)
├── contrib/                      # Community contributions
│   ├── grafana/                  # Grafana dashboard JSON
│   └── systemd/                  # systemd unit file
├── docs/                         # Documentation source (mkdocs)
├── integration/                  # End-to-end / integration test suite
│   ├── fixtures/                 # Per-scenario YAML/TOML Traefik configs (~30 scenarios)
│   ├── resources/compose/        # Docker Compose files for test environments
│   ├── testdata/                 # Supporting test data (certs, payloads)
│   └── try/                      # HTTP retry helper for integration tests
├── internal/                     # Project tooling (NOT the application's internal packages)
│   ├── release/                  # Release scripts/tooling
│   └── testsci/                  # CI test infrastructure helpers
├── pkg/                          # All application code (738 .go files total)
│   ├── api/                      # REST API handler and dashboard backend
│   │   └── dashboard/            # Dashboard-specific API routes
│   ├── cli/                      # Config loader implementations (file, flag, env, deprecation)
│   ├── collector/                # Anonymous usage statistics collection
│   │   └── hydratation/          # Config feature hydration for stats
│   ├── config/                   # Configuration type system
│   │   ├── dynamic/              # Dynamic config types: routers, services, middlewares, TLS
│   │   │   └── ext/              # Extension config types (e.g., for plugins)
│   │   ├── kv/                   # Key-value store config encoding/decoding
│   │   ├── label/                # Docker label parsing into config
│   │   ├── runtime/              # Runtime config state (adds status/health to dynamic config)
│   │   └── static/               # Static config types: entrypoints, providers, metrics, tracing
│   ├── healthcheck/              # Backend service health checking
│   ├── ip/                       # IP address parsing and strategy utilities
│   ├── job/                      # Background job lifecycle management
│   ├── middlewares/              # ~30 HTTP middleware implementations, one package each
│   │   ├── accesslog/            # Structured access logging (JSON + CLF)
│   │   ├── auth/                 # Basic auth, forward auth, digest auth
│   │   ├── circuitbreaker/       # Circuit breaker (via oxy)
│   │   ├── compress/             # Gzip/Brotli/zstd response compression
│   │   ├── headers/              # Request/response header manipulation + HSTS/CORS
│   │   ├── ratelimiter/          # Token-bucket rate limiting
│   │   ├── retry/                # Request retry with backoff
│   │   ├── gatewayapi/           # Gateway API spec middleware (header modifier, redirect, URL rewrite)
│   │   ├── ingressnginx/         # nginx-compatible ingress annotation support
│   │   ├── tcp/                  # TCP-level middlewares (IP allowlist, in-flight conn limit)
│   │   └── ...                   # (20+ more: redirect, stripprefix, chain, buffering, etc.)
│   ├── muxer/                    # Routing muxers
│   │   ├── http/                 # HTTP router matching (host, path, headers, query)
│   │   └── tcp/                  # TCP router matching (SNI, HostSNI)
│   ├── observability/            # Observability stack
│   │   ├── logs/                 # Structured log field constants and helpers
│   │   ├── metrics/              # Metrics registries (Prometheus, OTel, Datadog, StatsD, InfluxDB)
│   │   ├── tracing/              # Distributed tracing (OpenTelemetry OTLP)
│   │   └── types/                # Shared observability config types
│   ├── ping/                     # /ping readiness/liveness endpoint
│   ├── plugins/                  # Plugin system (WASM via wazero + Go scripting via yaegi)
│   ├── provider/                 # All provider implementations
│   │   ├── acme/                 # ACME/Let's Encrypt certificate provider
│   │   ├── aggregator/           # Multi-provider aggregator (the Provider of providers)
│   │   ├── consulcatalog/        # Consul Catalog service discovery
│   │   ├── docker/               # Docker / Docker Swarm service discovery
│   │   ├── ecs/                  # AWS ECS service discovery
│   │   ├── file/                 # File-based static/dynamic config
│   │   ├── http/                 # HTTP endpoint config polling provider
│   │   ├── kubernetes/           # Kubernetes integrations
│   │   │   ├── crd/              # Traefik CRDs (IngressRoute, Middleware, etc.)
│   │   │   ├── gateway/          # Kubernetes Gateway API implementation
│   │   │   ├── ingress/          # Standard Ingress resource support
│   │   │   ├── ingress-nginx/    # nginx-compatible Ingress annotation support
│   │   │   ├── k8s/              # Shared Kubernetes client helpers
│   │   │   └── knative/          # Knative serving integration
│   │   ├── kv/                   # Key-value store providers (Consul, etcd, Redis, ZooKeeper)
│   │   ├── nomad/                # HashiCorp Nomad service discovery
│   │   ├── rest/                 # REST API provider (dynamic config via API)
│   │   ├── tailscale/            # Tailscale certificate provider
│   │   └── traefik/              # Internal provider (ping, API, dashboard routing)
│   ├── proxy/                    # HTTP reverse proxy backends
│   │   ├── fast/                 # Experimental fast proxy (bypasses net/http)
│   │   └── httputil/             # Standard net/http/httputil-based proxy builder
│   ├── redactor/                 # Credential redaction for config logging
│   ├── rules/                    # Routing rule DSL parser
│   ├── safe/                     # Safe goroutine launch wrappers (safe.Go, safe.Pool)
│   ├── server/                   # Core server: entrypoints, routing, config watching
│   │   ├── middleware/           # Observability middleware wiring and builder
│   │   │   └── tcp/              # TCP middleware builder
│   │   ├── provider/             # Provider throttling wrapper
│   │   ├── recursion/            # Anti-recursion detection for self-referential routes
│   │   ├── router/               # HTTP router construction from dynamic config
│   │   │   ├── tcp/              # TCP router construction
│   │   │   └── udp/              # UDP router construction
│   │   └── service/              # Service manager and load balancer
│   │       ├── loadbalancer/     # Weighted round-robin load balancer
│   │       ├── tcp/              # TCP service manager
│   │       └── udp/              # UDP service manager
│   ├── tcp/                      # TCP connection handling and dialer
│   ├── testhelpers/              # Shared test utilities (request builders, etc.)
│   ├── tls/                      # TLS certificate store and manager
│   │   └── generate/             # Self-signed certificate generation
│   ├── types/                    # Shared domain types (headers, error pages, etc.)
│   ├── udp/                      # UDP connection handling
│   └── version/                  # Version string and new-version checker
├── script/                       # Changelog generation (gcg tool)
├── webui/                        # Vue.js dashboard (built separately, embedded in binary)
│   ├── src/                      # Vue.js source
│   ├── static/                   # Compiled static assets (committed/generated)
│   └── public/                   # Public assets
├── Dockerfile                    # Runtime image (Alpine, single-stage, copies pre-built binary)
├── Makefile                      # Build orchestration
├── generate.go                   # go:generate entry point (invokes cmd/internal/gen)
├── go.mod / go.sum               # Module definition
├── traefik.sample.toml           # Example static config (TOML)
└── traefik.sample.yml            # Example static config (YAML)

Entry points#

FilePurpose
cmd/traefik/traefik.goMain traefik binary — CLI bootstrap via paerser/cli, then setupServer() which wires providers, observability, entrypoints, plugin builder, router factory, and configuration watcher
cmd/healthcheck/healthcheck.goImplements the traefik healthcheck sub-command (HTTP GET to /ping)
cmd/version/version.goImplements the traefik version sub-command
cmd/internal/gen/main.goInternal code generator — produces dynamic/static config documentation reference files (not a shipped binary)

There is a single shipped binary: traefik. The healthcheck and version sub-commands are registered as sub-commands of the main CLI, not separate binaries.

Package organization#

  • Internal packages: The cmd/internal/gen package is the only true internal/ package, isolating the code generator. The application itself does not use Go’s internal/ mechanism to restrict imports within pkg/ — all packages are openly importable within the module.

  • Public packages (pkg/): All 20+ top-level packages under pkg/ form the application’s core. Key groupings:

    • Configuration layer: config/static, config/dynamic, config/runtime — three distinct config models
    • Provider layer: provider/* — each integration is isolated in its own package
    • Server layer: server/ — entrypoints, router factory, watcher, service manager
    • Middleware layer: middlewares/* — one package per middleware, strictly isolated
    • Observability layer: observability/metrics, observability/tracing, observability/logs
    • Protocol layers: tcp/, udp/, muxer/http, muxer/tcp — protocol handling separated from HTTP application logic
  • Layering:

    Static config (pkg/config/static)
         ↓ loaded by CLI loaders (pkg/cli)
    Provider Aggregator (pkg/provider/aggregator)
         ↓ pushes Dynamic config (pkg/config/dynamic)
    Configuration Watcher (pkg/server — ConfigurationWatcher)
         ↓ triggers
    Router Factory (pkg/server — RouterFactory)
         ↓ builds
    Muxers (pkg/muxer/http, pkg/muxer/tcp)
       + Middleware chain (pkg/middlewares/*)
       + Service managers (pkg/server/service)
         ↓ handle traffic via
    TCP/UDP Entrypoints (pkg/server — server_entrypoint_tcp.go, _udp.go)

    This is a clean layered architecture with a clear separation between configuration ingestion and request handling. Packages have well-defined responsibilities and generally flow in one direction.

Build system#

  • Build tool: GNU Make (Makefile) as the primary orchestrator
  • Key targets:
    • make generate — runs go generate (invokes cmd/internal/gen) to produce config documentation reference files
    • make binary — produces the traefik binary in dist/
    • make generate-webui — builds the Vue.js dashboard via a Docker image (traefik-webui), placing compiled assets in webui/static/
    • make default — runs generate then binary
    • The binary embeds the compiled WebUI static assets
  • Dockerfile: Single-stage Alpine image — the binary is pre-built by the CI pipeline and simply copied in. Multi-stage build is not used in the committed Dockerfile; GoReleaser handles cross-compilation in CI.
  • Docker: Yes — the published image is Alpine-based, non-root-friendly, with the traefik binary as the entrypoint. Multi-platform builds (linux/amd64,linux/arm64) via DOCKER_BUILD_PLATFORMS Makefile variable.

Notable structural decisions#

  1. One package per middleware (not a registry of functions). Each of the 30+ middlewares lives in its own sub-package (pkg/middlewares/ratelimiter/, pkg/middlewares/compress/, etc.) with its own types, tests, and concerns. This prevents accidental coupling between middlewares and makes it easy to add or remove individual middleware implementations. The contrast with projects that put all middleware in a single file or package is stark.

  2. Three-layer configuration model. Traefik explicitly separates static config (loaded once at startup: entrypoints, providers, metrics backends), dynamic config (live-reloaded routing rules pushed by providers), and runtime config (dynamic config augmented with health/status for the API). Each is a distinct package with distinct types — a deliberate architectural boundary preventing the conflation of infrastructure config with live routing state.

  3. Provider-as-plugin pattern, without a plugin mechanism. Each infrastructure integration (Docker, Kubernetes Ingress, Gateway API, Consul, etcd, Nomad, ECS, file, HTTP, REST) is a self-contained package under pkg/provider/. They all implement a common Provider interface, and the aggregator package fans them all out. This gives Traefik compile-time extensibility that mirrors a plugin system without the complexity of dynamic loading.

  4. WebUI embedded in the binary. The Vue.js dashboard is a separate frontend application in webui/, built via a dedicated Docker image and Makefile target. The compiled static assets end up in webui/static/ and are embedded into the Go binary (via go:embed or equivalent), so Traefik ships as a single self-contained executable with a full dashboard.

  5. pkg/safe as a first-class package. Goroutine safety and lifecycle management are important enough to warrant their own package (safe.Go, safe.Pool, safe.Goroutine). This reflects a deliberate choice to centralize error handling for goroutines — a common source of silent failures in Go services — rather than sprinkling go func() calls throughout.

  6. Integration tests fully separated with fixture configs. The integration/ directory is a self-contained test suite with per-scenario YAML/TOML Traefik configurations, Docker Compose files, and TLS fixtures. This allows integration tests to be run against a real Traefik instance rather than unit-test mocks, reflecting the project’s emphasis on correctness in realistic deployments.