Caddy foundations
Format, adapt, and validate
Format a Caddyfile, inspect the native JSON it produces, and run the stronger validation check before loading it.
10 minute lesson
Before you trust a Caddyfile, Caddy gives you three commands to check it. Each one goes deeper than the last.
First, formatting. caddy fmt rewrites your Caddyfile with consistent indentation:
caddy fmt --diff Caddyfile
The --diff flag shows what would change without touching the file. Add --overwrite when you want to apply it. Formatting sounds cosmetic, but it keeps diffs in version control readable, and Caddy logs a warning at startup when the file isn’t formatted.
Second, adaptation. This converts the Caddyfile to Caddy’s native JSON and shows you the result:
caddy adapt --config Caddyfile --pretty
Read that JSON once, even if it looks verbose. You’ll see the routes Caddy actually built, in the order it will try them, plus configuration that was implicit in the Caddyfile. When routing behaves strangely, this output is where you find out why.
Third, validation:
caddy validate --config Caddyfile
caddy validate goes further than adaptation. It loads the configuration and provisions every module, as if the server were starting for real — it just doesn’t open any sockets. A Caddyfile can adapt fine and still fail validation, for example when a tls directive references a certificate file that doesn’t exist on disk.
On success it prints that the configuration is valid. Make the full sequence a habit: format, adapt, validate, and only then load the configuration on a real server. It catches typos on your laptop instead of in production.
One thing validation cannot catch: runtime problems. It won’t tell you that port 443 is already taken or that DNS doesn’t point at your machine. It checks the configuration, not the environment. Keep that boundary in mind when a valid config still fails to start.
Lesson completed