Skip to content
| Marketplace
Sign in
Visual Studio Code>Linters>ComposeVars: Docker Compose Variable CheckerNew to Visual Studio Code? Get it now.
ComposeVars: Docker Compose Variable Checker

ComposeVars: Docker Compose Variable Checker

jaytank_dev

| (0) | Free
Catch unset ${VAR} interpolation in docker-compose.yml / compose.yaml before `docker compose up`: checks against .env, .env.example and --env-file, flags missing env_file paths, host-side $VAR in command:, and committed secret defaults - values masked.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

ComposeVars

Docker Compose variable checker for VS Code. Catch the blank ${VAR} before docker compose up does.

Docker Compose fills ${VAR} in your compose file from your shell and the project .env file. When a variable is missing, Compose does not fail - it substitutes an empty string and prints one easy-to-miss line at runtime:

WARN[0000] The "DB_HOST" variable is not set. Defaulting to a blank string.

The result is an image tag of nginx:, a port mapping of :80, or a database URL with no host - discovered after the stack is already up. A second, very common confusion is between the project .env file (used only for interpolation inside the compose file) and env_file: (variables passed into the container).

ComposeVars checks all of this statically, in the editor, against the files that Compose itself would read.

Evidence that this bites people:

  • docker/compose#5505 - "Make docker-compose fail when an undefined environment variable used in a compose file."
  • docker/compose#9031 - inconsistent pass-through behavior between environment and env_file.
  • docker/compose#11740 - environment entries with no value vs env_file precedence.
  • Docker docs: Variable interpolation, Set environment variables, Precedence.

What it reads

For every docker-compose*.yml, compose*.yaml (including override files such as compose.override.yaml) and every file pulled in through include: or extends: file::

Source How it is used
.env next to the compose file (the project directory) Interpolation values, as Compose loads them by default
--env-file <path> and COMPOSE_ENV_FILES=... found in package.json scripts, Makefile or justfile Extra interpolation sources for compose files at or below that script's folder
include: entries The included file uses its own folder's .env (or the env_file: given on the include), and the including project's variables take precedence, as documented
.env.example, .env.sample, .env.template, .env.dist, example.env The "documented" set - variables your team expects to be provided
env_file: paths Checked for existence (relative to the compose file)

Interpolation syntax (as Compose implements it)

Behavior verified against the Compose interpolation reference, the variable interpolation guide and the compose-go template implementation.

Syntax Meaning ComposeVars
${VAR} / $VAR Value of VAR; blank with a runtime warning if unset CV001 if not set anywhere it can see
${VAR:-default} default if VAR is unset or empty OK (CV006 if a secret has a default)
${VAR-default} default only if VAR is unset OK (CV006 if a secret has a default)
${VAR:?message} Error and stop if unset or empty OK - the recommended way to require a variable
${VAR?message} Error and stop if unset OK
${VAR:+alt} / ${VAR+alt} alt if set (and non-empty for :+), otherwise blank, no warning OK
${A:-${B:-x}} Nested defaults are allowed Inner variables are only checked when the outer one would actually fall through
$$ A literal $ (escape) Never reported
$1, $@, $ Not a valid variable name - Compose leaves it as-is Never reported

Only YAML values are interpolated, never keys.

Rules

Code Severity Bad Good
CV001 unset variable Warning (Information if it is in .env.example but missing from .env) image: "app:${TAG}" with no TAG in .env TAG=1.4 in .env, or ${TAG:-latest}, or ${TAG:?TAG is required}
CV002 .env key never used Information (in the .env file) .env: API_KEY=... and nothing references it Use env_file: .env or environment: [API_KEY] if the container needs it - the project .env only feeds ${...} in the compose file
CV003 pass-through env not set Information environment: [DEBUG] or DEBUG: with no value and no DEBUG in .env Add DEBUG=... to .env, or give it a value. Compose silently omits it otherwise
CV004 missing env_file Error env_file: ./web.env that does not exist Create the file, fix the path, or - path: ./web.env + required: false (Compose 2.24+)
CV005 host-side $VAR in a command Warning command: sh -c 'echo $HOME' - Compose substitutes the host's HOME when loading the file command: sh -c 'echo $$HOME' so the container shell expands it
CV006 committed secret default Warning ${DB_PASSWORD:-hunter2} ${DB_PASSWORD:?DB_PASSWORD is required}

CV005 applies to command:, entrypoint: and healthcheck.test, including block scalars (| / >), and only to names that are not defined in any env file you use (those are clearly meant as Compose variables).

CV006 uses a name pattern (*_PASSWORD, *_SECRET, *_TOKEN, *_KEY and similar, configurable). The default value is never shown in the message, hover or report.

Quick Fixes

  • CV001: make the blank explicit (${VAR:-}), require it (${VAR:?VAR is required}), or add VAR= to .env.example (created if missing; the value is left empty).
  • CV003: add the key to .env.example.
  • CV005: escape as $$, or add the name to .env.example if it really is a Compose variable.
  • CV006: replace the committed default with ${VAR:?VAR is required}.

The same fixes are available from the lightbulb on each row of the ComposeVars view.

Activity bar

  • Activity bar view. The ComposeVars icon in the activity bar opens a Findings view: one row per finding, labelled with the rule code and the exact variable (for example CV001 DB_PASSWORD, CV004 ./web.env), grouped by compose file when there are several, with the rule and line next to it and the full message in the tooltip. Click a row to jump to the line; the lightbulb on a row applies a Quick Fix where one exists. The icon badge shows the number of findings, and the title bar has Show Resolved Variables and Rescan Workspace. Values are never shown in the view.

Hover and report

Hover any ${VAR} or $VAR to see where its value comes from - for example .env line 4, --env-file (package.json line 3), default in compose file, or unset - blank unless exported in your shell - and the resulting value. Secret-looking values are always masked, and so is the password part of any URL value (postgres://app:****@db/app).

ComposeVars: Show Resolved Variables opens a Markdown table per compose file: variable, line, source and (masked) value, plus the interpolation sources in precedence order. The status bar shows the number of findings; click it to open the same report.

How this differs from existing tools

  • Docker DX (docker.docker, built on the Docker Language Server) gives Compose files completion, hover, outline, navigation, rename, formatting, inlay hints for overridden values, and document links / path completion for env_file:. Its Compose diagnostics report YAML syntax errors. It does not report unset ${VAR} interpolation, unused .env keys, missing env_file files, or $ escaping.
  • Container Tools / Docker extension by Microsoft (Docker Compose Language Service) offers hover docs, completions, formatting and CodeLens; its diagnostics validate YAML only. It does not resolve variables against .env.
  • dclint (Docker Compose Linter) has style, security and best-practice rules (ordering, quotes, ports, image tags, container names). None cover interpolation or env files.
  • hadolint lints Dockerfiles, not compose files.
  • docker compose config resolves variables at the command line and prints the same runtime warning - useful, but only when you run it, and it prints secrets in clear text.

ComposeVars is complementary to all of these: it only does variables and env files, and it does them in the editor.

Settings

Setting Default Description
composeVars.enable true Turn diagnostics on or off.
composeVars.ignoreVariables HOME, USER, PATH, PWD, SHELL, LANG, TERM, LOGNAME, TMPDIR Variables every shell exports. Not reported by CV001/CV003; still reported by CV005 inside commands.
composeVars.secretPattern (^\|_)(PASSWORD\|PASSWD\|PASS\|SECRET\|TOKEN\|KEY\|APIKEY\|CREDENTIALS?)$ Case-insensitive regex for secret-looking names (masked, CV006).
composeVars.maskAllValues false Mask every value, not only secret-looking ones.
composeVars.disabledRules [] Rule codes to turn off, e.g. ["CV002"].
composeVars.scanScripts true Read package.json, Makefile, justfile for --env-file / COMPOSE_ENV_FILES.
composeVars.maxFiles 200 Maximum compose files scanned per workspace.

Commands

  • ComposeVars: Show Resolved Variables - Markdown report of every variable, its source and masked value.
  • ComposeVars: Rescan Workspace - re-read all compose and env files. Changes are also picked up on save, by a file watcher, and by a light check every 15 seconds while the window is focused (for file systems where watching does not work).

Privacy

  • Workspace-only file access. ComposeVars only ever reads, checks or edits files inside your open workspace folders. An env_file, include env file, --env-file or COMPOSE_ENV_FILES path that points outside the workspace (for example ../../.aws/credentials or /etc/passwd) is never opened, never probed for existence and never shown, and Quick Fixes never create files outside the workspace. Symlinks are resolved first, so a .env, compose file or folder inside the repository that links to a file outside it is ignored too. FIFOs, devices and files over 2 MB are never read. This holds in untrusted workspaces too.

  • No network access, no telemetry, no child processes. Everything is read from local files.

  • Works in untrusted workspaces, because it only reads files. There, a composeVars.secretPattern from the workspace's own settings is ignored, so a repository cannot switch masking off.

  • Secret-looking values are masked everywhere ComposeVars displays something: hovers, the report and diagnostic messages. Values are never written anywhere; the only edits are the Quick Fixes you choose.

Limitations

  • Your shell environment is not visible to an editor extension. A variable you always export before running Compose will be reported by CV001; add it to composeVars.ignoreVariables or to .env.
  • -f file lists, COMPOSE_FILE and --project-directory on the command line are not modeled; each compose file uses the .env in its own folder. --env-file values found in scripts are treated as always applied (a union), which can hide a variable that is only set for one script.
  • The YAML reader is line-oriented. It handles block maps and sequences, flow lists on one line, comments and block scalars, but not multi-line flow collections or YAML anchors merged across services.
  • Variables in env_file contents are not checked (they are container env, not interpolation).
  • Profiles are ignored: a variable used only by an inactive profile is still reported.

License

MIT - included with the extension.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft