Open-Source Wikis

/

CoreDNS

/

Systems

/

Build and code generation

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

They 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 as github.com/coredns/coredns/plugin/forward.
  • A fully qualified import path like on:github.com/coredns/caddy/onevent for 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 gen

directives_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 EDIT

The 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 under man/ from each plugin's README.md. The make.doc workflow 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.cfg in the correct execution position, then run make gen.
  • Adding an out-of-tree plugin to the binary → add a fully-qualified line to plugin.cfg (or set COREDNS_PLUGINS).
  • Reordering execution → reorder plugin.cfg. Be aware that downstream plugins assume a specific order (e.g., metadata must run before plugins that rely on metadata).
  • Adding a new build-time variable → declare it in coremain/run.go and add it to the Makefile's LDFLAGS.
  • Regenerating man pages → make -f Makefile.doc.
  • Updating ownership of a plugin → edit plugin/<name>/owners.json and run go run owners_generate.go.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Build and code generation – CoreDNS wiki | Factory