coredns/coredns
Build and code generation
Active contributors: miekg, chrisohaver, johnbelamaric
Purpose
CoreDNS uses a tiny code-generation step to bake the plugin list into the binary. The single source of truth is plugin.cfg; two generators turn it into Go files that the rest of the codebase imports. This page explains those generators, the generated files, and how the Makefile ties them together.
The pipeline
graph LR
A[plugin.cfg] --> B[directives_generate.go]
B --> C[core/plugin/zplugin.go]
B --> D[core/dnsserver/zdirectives.go]
A --> E[owners_generate.go]
E --> F[CODEOWNERS]
G[plugin/*/owners.json] --> E
C -->|blank import| H[main]
D -->|Directives slice| I[Caddy server type]The coredns.go file has two go:generate directives:
//go:generate go run directives_generate.go
//go:generate go run owners_generate.goThey are run by make gen (or go generate coredns.go).
plugin.cfg
A flat text file. Each line is <directive>:<package> where <package> can be either:
- A bare name like
forward— interpreted asgithub.com/coredns/coredns/plugin/forward. - A fully qualified import path like
on:github.com/coredns/caddy/oneventfor plugins that live outside the repo.
Comments start with #. The order of lines in plugin.cfg is the execution order of plugins in the chain. Reordering this file changes how a request flows.
The COREDNS_PLUGINS environment variable can extend the list at generate time:
COREDNS_PLUGINS=example:github.com/coredns/example make gendirectives_generate.go reads os.Getenv("COREDNS_PLUGINS"), splits on commas, and merges the entries into the same plugin map.
directives_generate.go
Run with //go:build ignore so it never compiles into the binary. Two outputs:
zplugin.go
core/plugin/zplugin.go is a long list of blank imports:
package plugin
import (
_ "github.com/coredns/coredns/plugin/forward"
_ "github.com/coredns/coredns/plugin/cache"
// ...
)It pulls every plugin into the binary so each plugin's init() registers it with Caddy. CoreDNS plugins are listed first; third-party imports follow in a separate import group.
zdirectives.go
core/dnsserver/zdirectives.go contains the ordered slice of directive names:
var Directives = []string{
"root",
"metadata",
// ... 60+ entries ...
}Caddy's server-type setup iterates this slice in order to drive each plugin's setup function. The slice is also exposed as dnsserver.Directives and surfaced via caddy.RegisterServerType so the Caddyfile parser knows which tokens are directives.
The header on both generated files reads:
// generated by directives_generate.go; DO NOT EDITThe verify-make-gen CI workflow runs make gen and fails if these files end up modified — keeping plugin.cfg and the generated outputs in sync on every PR.
owners_generate.go
Walks plugin/*/owners.json (when present) and updates the CODEOWNERS file in the repo root. Each plugin can declare its maintainers in owners.json; the generator merges those into the global file.
The header at the top of CODEOWNERS lists the steering committee. The per-directory entries below are auto-managed.
Makefile targets
The top-level Makefile ties everything together:
| Target | Effect |
|---|---|
make (default all: coredns) |
make check then go build with -ldflags="-s -w -X coremain.GitCommit=..." |
make check |
Re-run go generate if plugin.cfg is newer than the generated files |
make gen |
Force go generate coredns.go && go get |
make pb |
Regenerate pb/dns.pb.go and pb/dns_grpc.pb.go from pb/dns.proto |
make clean |
Remove the binary |
There are three companion Makefiles:
Makefile.docker— builds Docker images for various architectures.Makefile.release— release pipeline used by the GitHub release workflow.Makefile.doc— regenerates the man pages underman/from each plugin'sREADME.md. Themake.docworkflow checks PRs for staleness.
CI checks for generated content
| Workflow | Purpose |
|---|---|
.github/workflows/verify-make-gen.yml |
Runs make gen, fails if it produces a diff |
.github/workflows/make.doc.yml |
Runs make -f Makefile.doc, fails on diff |
.github/workflows/golangci-lint.yml |
Runs golangci-lint |
.github/workflows/go.test.yml |
Runs go test ./... |
.github/workflows/codeql-analysis.yml |
Static analysis |
.github/workflows/cifuzz.yml |
OSS-Fuzz harness invocation |
See Tooling for the rest.
Key files
| File | Purpose |
|---|---|
plugin.cfg |
Source of truth for plugin list and directive order |
directives_generate.go |
Generator for zplugin.go and zdirectives.go |
owners_generate.go |
Generator for CODEOWNERS |
core/plugin/zplugin.go |
Generated blank imports |
core/dnsserver/zdirectives.go |
Generated ordered directive slice |
coredns.go |
Hosts the go:generate lines |
Makefile |
make, make check, make gen, make pb |
Makefile.doc |
Man page regeneration |
pb/dns.proto |
gRPC service definition |
Entry points for modification
- Adding a new in-tree plugin → add a line to
plugin.cfgin the correct execution position, then runmake gen. - Adding an out-of-tree plugin to the binary → add a fully-qualified line to
plugin.cfg(or setCOREDNS_PLUGINS). - Reordering execution → reorder
plugin.cfg. Be aware that downstream plugins assume a specific order (e.g.,metadatamust run before plugins that rely on metadata). - Adding a new build-time variable → declare it in
coremain/run.goand add it to the Makefile'sLDFLAGS. - Regenerating man pages →
make -f Makefile.doc. - Updating ownership of a plugin → edit
plugin/<name>/owners.jsonand rungo run owners_generate.go.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.