use-exec-form
Docker container takes 10 seconds to stop? Shell form CMD swallows SIGTERM. How exec form fixes signal handling and graceful shutdown.
On this page
CMD node server.js (shell form) doesn't run your app as PID 1 — it runs /bin/sh -c "node server.js", and the shell becomes PID 1 with your app as its child. When Docker sends SIGTERM on docker stop, the shell receives it and does not forward it. Your app never hears the shutdown request. This rule flags shell-form CMD and ENTRYPOINT instructions.
What the rule catches
FROM node:22-slim
WORKDIR /app
COPY . .
CMD node server.jsScanning this file reports:
⚠ WARN [docker-doctor/use-exec-form]
CMD instruction uses shell form instead of exec form. In shell form, the command runs under '/bin/sh -c', which does not pass signals to child processes.Why it matters
The visible symptom is every docker stop and every rolling deploy hanging for the 10-second grace period and ending in SIGKILL. The invisible symptom is worse: your graceful-shutdown code — draining requests, closing database connections, flushing queues — never runs, because the process is killed, not asked to exit. Exec form (CMD ["node", "server.js"]) makes your app PID 1 so signals reach it directly.
How to fix it
Write CMD/ENTRYPOINT instructions as JSON arrays (e.g. ENTRYPOINT ["node", "index.js"]) so OS signals (like SIGTERM) are forwarded correctly.
FROM node:22-slim
WORKDIR /app
COPY . .
CMD ["node", "server.js"]Exec form is a JSON array, so it must use double quotes, and there is no shell: $VAR, pipes, and && won't work inside it. If you genuinely need shell features at startup, wrap them in an entrypoint script that ends with exec node server.js — exec replaces the shell so the app still ends up as PID 1. Then make sure the app actually handles SIGTERM; PID 1 gets no default signal handlers.
Rule details
- Rule key —
docker-doctor/use-exec-form - Category — Best Practices
- Default severity —
warning - Applies to — Dockerfiles
Explain this rule from the CLI:
npx @docker-doctor/cli@latest rules explain docker-doctor/use-exec-formChange its severity — or turn it off — in your config file:
// docker-doctor.config.ts
export default {
rules: {
"docker-doctor/use-exec-form": "off",
},
};Severity affects the health score: error findings cost more points than warning, and info costs the least.