NV ToolkitFormat · Validate · Convert

YAML Tools

Docker Compose Validator — Schema + Reference Checks

Syntax, schema and cross-reference errors in one report — catch a broken compose file before docker compose up does it for you.

In short

Validate a docker-compose.yml online against the Compose Specification schema, plus checks for undeclared volumes, networks and depends_on targets — every error with its line.

By NaveenKumar T · Updated

  • Compose Specification JSON Schema (Ajv)
  • Errors mapped to YAML line & column
  • Undeclared volume / network / secret checks

Runs entirely in your browser — nothing you paste or open here is uploaded, logged, or stored.How we handle data →

Example

Docker Compose Validator: input and output

A three-service compose file with three deliberate mistakes: an obsolete version key, a typo'd enviroment key under web, and a named volume mounted by db that was never declared at the top level.

Input · docker-compose.yml
version: "3.8"
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    enviroment:
      - API_URL=https://api.example.com
    depends_on:
      - api
  api:
    image: myorg/api:1.0
    networks:
      - appnet
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data

networks:
  appnet: {}
Output · validation report
✗ Invalid — 1 schema error, 2 lint findings

Services  3 · Volumes  0 · Networks  1 · Schema  compose-spec @ 2026-09-17

line 1, col 1 — version: obsolete under the Compose Specification — docker compose ignores it and prints a warning; remove it (version) [warning]
line 7, col 5 — services.web.enviroment: unknown key "enviroment": must NOT have unevaluated properties (unevaluatedProperties)
line 17, col 5 — services.db.volumes: service refers to undefined volume "pgdata" — declare it under the top-level volumes key (volumes)

Three findings, each on its own reported line: the obsolete version key (a warning, not an error), enviroment rejected because it doesn't match any known service key and isn't an x- extension, and pgdata flagged as an undeclared volume because the file never adds a top-level volumes: section for it.

Learn more

Syntax, schema, semantics: the three ways a compose file breaks

A Docker Compose file can be broken at three completely different levels, and knowing which one you're looking at is most of the debugging work. SYNTAX errors are YAML problems — a tab where a space belongs, a missing colon, inconsistent indentation — and they stop the file from parsing at all. SCHEMA errors are Compose-specific: the YAML parses fine, but the document doesn't match the shape a Compose file is supposed to have — a typo'd key like enviroment, a value of the wrong type, a field that doesn't belong where it was placed. SEMANTIC errors are the subtlest: every individual value is shaped correctly, but the file is internally inconsistent — a service mounts a named volume that was never declared under the top-level volumes: key, or depends_on names a service that doesn't exist anywhere in the file.

This validator checks all three, in that order, in one pass: a YAML parse first (with the yaml package's own line/column-accurate error reporting), then the full document against the official Compose Specification's JSON Schema using Ajv's 2020-12 build (the schema itself declares draft 2020-12), then eight targeted cross-reference checks the schema's own vocabulary has no way to express — checks 3 through 5 below are exactly this kind of cross-reference problem, comparing one part of the document against another rather than checking one value in isolation.

Eight checks the schema cannot express

A JSON Schema validates one location in a document against a rule that only looks at that location — it has no native way to say "this value over here must match a key that exists somewhere else in the document." That's exactly the gap these eight checks close, run after schema validation whenever Scope is set to Schema + reference checks.

The eight semantic checks
#CheckSeverityWhy the schema can't express it
L1version: key is presentWarningThe schema accepts it for backward compatibility — its own description calls it ignored, but accepting isn't the same as flagging
L2depends_on names a service that isn't under servicesErrorCross-reference between two different parts of the document
L3A named volume mount isn't declared under top-level volumesErrorCross-reference; bind mounts (paths, ./ or ~) are correctly excluded
L4A service networks entry isn't declared under top-level networksErrorCross-reference (the implicit default network is exempt)
L5A secrets/configs reference isn't declared at the top levelErrorCross-reference
L6The same host port is published by two servicesWarningCross-SERVICE comparison — the schema validates one service at a time
L7container_name is set together with more than one replicaErrorA co-occurrence rule across two unrelated-looking fields
L8A service has neither image nor buildErrorA conditional requirement the schema's boolean logic doesn't encode here

What this validator does not do, and what docker compose config does

Being honest about scope matters more than looking thorough: this page performs static analysis of the file exactly as written. It does not resolve ${VARIABLE} interpolation against your shell environment or a .env file, does not follow include: or extends: across other files, does not apply profiles:, does not check that an image reference actually exists in a registry, and does not check whether a host port is genuinely free on your machine. Those all require a live environment this validator deliberately doesn't have access to, since nothing you paste here ever leaves your browser.

docker compose config is the command that picks up exactly where this leaves off: it resolves every one of those, merges included files, and either prints the fully-resolved configuration or a specific error naming what's missing.

Two commands that pick up the rest
CommandWhat it adds beyond this validator
docker compose configResolves ${VAR} interpolation, merges include/extends, applies profiles, prints the final config
docker compose config --quietSame resolution, but only exits non-zero on error — good for a CI gate

Reading a finding

Every line in the report follows one format: line N, col M — path: message (keyword). The path is the dotted location inside the document (services.web.ports, for instance), and the keyword in parentheses is either an Ajv schema keyword (additionalProperties, required, type) or one of the eight semantic check codes from the table above, so you always know whether a finding came from the official schema or from this page's own cross-reference logic.

One more thing worth knowing before a report looks noisier than expected: the Compose Specification schema leans heavily on oneOf and anyOf for fields that accept several shapes (ports, volumes, depends_on, command — all of them can be written more than one way), and Ajv reports one full error per shape that a bad value failed to match. A single malformed ports entry can otherwise produce three or four nearly-identical lines. This validator groups those by location and keeps only the summary line plus the single most specific branch error, so one real mistake reads as one or two report lines instead of a wall of near-duplicates.

Help

Frequently asked questions

Everything you need to know about the Docker Compose Validator.

01How do I use this docker compose validator?

Paste or drop your compose.yml (or click Sample for a working three-service file) and press Validate. The report runs in three layers: YAML syntax first, then the file's shape against the official Compose Specification JSON Schema, then eight cross-reference checks the schema itself can't express — an undeclared volume, a depends_on target that doesn't exist, and similar mistakes. Every finding is reported as line N, col M so you can jump straight to it; the Scope switch turns the third layer off if you only want schema conformance.

02How is this different from the YAML Validator?

The same split this site already makes between /json-validator and /json-schema-validator, applied to Compose files: the YAML Validator checks only that a file is SYNTACTICALLY correct YAML — indentation, quoting, matched brackets — with no idea what a Compose file is supposed to contain. This page runs that same syntax check first, then adds two more layers: is the STRUCTURE a valid Compose file (the right keys, in the right shape, per the official Compose Specification schema), and do the CROSS-REFERENCES inside it hold together (does every volume, network, secret and depends_on target actually exist elsewhere in the file). A file can be perfect YAML and still be an invalid Compose file — enviroment: instead of environment: parses as fine YAML and fails here as an unknown key.

03Why does it warn about version: "3.8" when every tutorial has it?

Because the Compose Specification — the schema this validator runs against — merged the old 2.x/3.x file-format versions into one single, versionless spec, and the schema's own description for the version field says it plainly: "declared for backward compatibility, ignored. Please remove it." docker compose itself prints "the attribute `version` is obsolete" the moment it sees the key. It's harmless to leave in an existing file — nothing breaks — but a huge number of tutorials and older Stack Overflow answers still show it out of habit, which is exactly why this validator flags it as a warning rather than silently accepting it.

04Why does enviroment fail but x-logging pass?

The Compose Specification schema locks each service down to its known key set with additionalProperties/unevaluatedProperties: false, but deliberately carves out one exception — any key starting with x- is explicitly allowed everywhere via a patternProperties: { "^x-": {} } rule, because x- keys are the spec's official mechanism for vendor extensions and YAML anchors (x-common: &common is the standard trick for sharing config between services). enviroment isn't an x- key, so it hits the lockdown and fails as an unrecognized property; x-logging matches the extension pattern and sails through untouched, whatever it contains.

05Does it check that images exist, ports are free, or ${VARIABLES} resolve?

No — this is static analysis of the file as written, not a live check against Docker or your environment. It does not pull images to confirm they exist, check whether a host port is actually free, resolve ${VAR} interpolation against a .env file or your shell's environment, or follow include/extends across files. docker compose config is the tool that does all of that: it resolves interpolation, merges included files, applies profiles, and prints the fully-resolved configuration (or a clear error if something's missing) — run it locally once this validator confirms the file is structurally sound, for the checks that genuinely need a live environment to answer.

06Which Compose file version does it validate against?

The Compose Specification schema at the pinned commit named in the report's header line (Schema compose-spec @ <date>) — the same specification docker compose itself implements today, which subsumes the legacy docker-compose v1 2.x and 3.x file formats rather than treating them as separate targets. The Compose Specification is actively maintained; if a very recent field is missing here, it's worth checking whether the vendored schema has simply fallen behind the spec's latest revision.

Keep working

Related tools