Safeguard
Security Guides•

Which distroless image fits Node.js, Java, Python and Go services?

Pick static for Go, a runtime image for Node.js, Java or Python, and use the nonroot tag. The debug tag adds a shell for troubleshooting only.

Safeguard Security Team
4 min read

For Go with no cgo use the static image, for Node.js, Java and Python use the matching runtime image, and prefer the nonroot tag for all of them. Distroless images contain only your app and its runtime dependencies, with no package manager or shell, so entrypoints must use exec form.

What the project publishes

The distroless project lists current images built on Debian 13. Based on its README, the families are static, base, base-nossl and cc for compiled code, java-base plus java17, java21 and java25 for Java, nodejs22, nodejs24 and nodejs26 for Node.js, and python3 for Python. Each family offers tags latest, nonroot, debug and debug-nonroot.

Your serviceImage familyNotes
Go without cgostaticIncludes certificates and tzdata
Go with cgo, Rust, Cbase, or ccAdds glibc, base also adds libssl
Node.jsnodejs plus major versionPick a version you support
Javajava plus 17, 21 or 25JRE style runtime, no shell
Pythonpython3Check which Python minor it carries

Architecture support varies by image, so confirm the list for your platform in the README table before you commit.

The tag choices

  • latest: the default tag. The README does not promise a non-root user, so treat it as root unless you check with the id command.
  • nonroot: the variant intended to run as a non-root user. Use this by default and verify it.
  • debug: adds a busybox shell, for troubleshooting.
  • debug-nonroot: debug with a non-root user.

The project says that if an image already has a tag such as the nonroot one, you use the debug tag with a matching prefix to get a shell. Keep debug images out of production.

Three things that surprise people

  1. No shell means ENTRYPOINT must be in exec form. The README shows that a string form entrypoint does not work, while a JSON array does.
  2. Static, base and cc images have an empty entrypoint by default, while the language images have a language specific default, so your CMD differs by family.
  3. Debugging uses a different approach. See debugging a distroless container with ephemeral containers rather than adding a shell to the image.

Verify before you build on them

The README states that all distroless images are signed with cosign using keyless signing, and recommends verifying any distroless image before you build on it, with the issuer and identity the project documents. It also says the images track upstream Debian releases and open update pull requests automatically. That is a good sign, but your image does not change until you rebuild.

Example for Node.js

FROM node:24-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .

FROM gcr.io/distroless/nodejs24-debian13:nonroot
WORKDIR /app
COPY --from=build /app /app
CMD ["server.js"]

For the language images the entrypoint is already the runtime, so CMD carries the script. Check the language README for the exact usage.

Where Safeguard fits

A distroless base shrinks operating system findings, but your dependencies remain. Safeguard scans them, builds an SBOM and uses reachability analysis to rank what matters. Policies can gate pull requests. Try the free scan.

Quick check

Is distroless the same as scratch?

No. Scratch is empty. Distroless images include a minimal Linux base with items such as certificates, and language images include the runtime.

Do I need the debug tag in production?

No. Use it temporarily in a non-production environment, or use ephemeral debug containers in your cluster.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.