Open-Source Wikis

/

Caddy

/

Systems

/

Context

caddyserver/caddy

Context

caddy.Context is the runtime environment passed to every module's Provision method. Defined in context.go (~25 KB).

Purpose

Wrap a Go context.Context with extra accessors that modules need:

  • A scoped zap logger named after the module's ID.
  • The ability to look up sibling apps and load child modules.
  • A handle on the configured certmagic.Storage, the configured filesystem, and other shared resources.
  • Cleanup-hook registration tied to the parent config's lifetime.

caddy.Context is the single most-imported type from the core package outside App and Module.

Directory layout

Path Role
context.go Context definition, LoadModule, LoadModuleByID, App, Logger, Storage, Filesystems
caddy.go The function that creates contexts during config load (unsyncedDecodeAndRun)

Key abstractions

Method Description
Context.LoadModule(parent, fieldName) Load a module from a json.RawMessage field on parent using its caddy:"namespace=…" tag
Context.LoadModuleByID(id, raw) Load a specific module by ID from a json.RawMessage
Context.App(name) Return the running app with that ID (or nil)
Context.AppIfConfigured(name) Like App, but returns (nil, true) if app is configured but failed to provision
Context.Logger() Return a zap logger named after the calling module's ID
Context.Storage() The configured global certmagic.Storage
Context.Filesystems() Map of named filesystems (caddy.filesystems.*)
Context.OnCancel(fn) Register a function to run when the context is canceled
Context.Slogger() Return an slog.Logger wrapping the same zap logger

How it works

graph TD
    Load[caddy.Load] -->|new Context per config| Ctx[caddy.Context]
    Ctx -->|Provision| Module
    Module -->|ctx.LoadModule| Child[child module]
    Module -->|ctx.App tls| TLSApp[tls app]
    Module -->|ctx.Logger| ZapLogger
    Reload[next config load] -->|cancel old ctx| Cleanup[CleanerUpper.Cleanup<br/>+ OnCancel hooks]

Where contexts come from

caddy.Load (in caddy.go) creates one root Context per config. Each app's Provision(ctx) runs against this root; when the app loads sub-modules (e.g. routes, matchers, handlers), it usually passes the same context or a derived one. The contexts form a tree, but the tree is implicit — there's no explicit hierarchy stored anywhere; everything dies together when the parent is canceled.

Module-scoped logger

ctx.Logger() walks up the call stack heuristically (looking at the type of the immediate caller via reflection) to determine which module it's being called from, then returns a zap logger named after that module's ID. The result is that every log line from http.handlers.file_server carries logger: http.handlers.file_server, and operators can filter on it.

App lookup

ctx.App("tls") returns the running TLS app. The HTTP app uses this to register hostnames; the events app provides the back-channel for cross-app notifications. If the app is not configured, the call returns nil, nil. If the app is configured but failed to provision (rare during normal operation), AppIfConfigured returns (nil, true) so callers can distinguish.

Cleanup

When the next caddy.Load swaps in a new config, the old root context is canceled. Anything registered through OnCancel runs, then every loaded module's Cleanup runs (if it implements CleanerUpper). Failure during cleanup logs but doesn't roll back — by the time we're cleaning up, the new config is already running.

Filesystems

Context.Filesystems() returns the registered filesystems. A custom filesystem (e.g. a virtual fs reading from an embedded FS) implements caddy.filesystems.* and can be referenced by name from handlers like the file server.

Integration points

  • Every Provision-implementing module receives one and uses ctx.Logger, ctx.LoadModule, ctx.App.
  • The HTTP app's Provision (modules/caddyhttp/app.go) is the canonical example: it loads server-level modules, asks for the TLS app via ctx.App, builds route trees, etc.
  • Tests using the caddytest harness get real Contexts — there's no mock context; tests run against an actual Caddy instance.

Entry points for modification

  • Don't store contexts in struct fields; that's against project convention (AGENTS.md). If you need a context.Context later, derive one from a request or a Server.
  • New per-context resource? Add a method on Context and a backing field in Config. Be conservative — every addition becomes part of the implicit module API.

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

Context – Caddy wiki | Factory