# Quickstart for Chainguard Containers

URL: https://edu.chainguard.dev/chainguard/chainguard-images/quickstart.md
Last Modified: August 5, 2026
Tags: Chainguard Containers, Getting Started

An end-to-end walkthrough of Chainguard Containers: pull a Free container, run a small Node.js application on it, and verify the image's signature and SBOM.

This quickstart covers one full cycle of working with a Chainguard Container: pull an image from Chainguard&rsquo;s registry, run your own code on it, and verify where it came from. The example uses the Node container, but the same workflow applies to every image in the Chainguard Containers Directory.
These steps link to reference documentation instead of explaining each concept in place. Follow the links whenever you want additional details and context.
Prerequisites To follow this quickstart, you need:
Docker or another OCI-compatible container runtime installed on your local machine. Cosign, which you use in Step 4 to verify a container image, installed. jq installed. jq is a lightweight, command-line JSON processor; this guide uses it in Step 4 to make Cosign output more easily readable. You don&rsquo;t need a Chainguard account. Every image in this guide is a Free Container: publicly available, with no authentication required. Production Containers, which add version-specific tags and patch SLAs, require authenticating to the registry.
Step 1: Pull and run a container Pull the Node container from cgr.dev, Chainguard&rsquo;s registry:
docker pull cgr.dev/chainguard/node:latestChainguard publishes two tags for Free Containers — latest and latest-dev — and both point at the most recent build of the image.
The image&rsquo;s entrypoint is node, so any arguments you pass go to the Node binary. Run the container, passing an argument to check the Node version:
docker run --rm cgr.dev/chainguard/node:latest --versionv26.6.0Your output may show a different version. Chainguard rebuilds its containers as upstream releases and package updates land, and the latest tag follows the newest build.
Step 2: Build your application on the container Create a directory for a demo application:
mkdir ~/hello-chainguard &amp;&amp; cd ~/hello-chainguardCreate a file named server.js to hold an example JavaScript application. It uses only the Node standard library, so the application has no dependencies to install:
cat &gt; server.js &lt;&lt;EOF const http = require(&#34;node:http&#34;); const server = http.createServer((req, res) =&gt; { res.writeHead(200, { &#34;Content-Type&#34;: &#34;application/json&#34; }); res.end(JSON.stringify({ message: &#34;Hello from a Chainguard Container&#34;, node: process.version, uid: process.getuid(), })); }); server.listen(8080, () =&gt; console.log(&#34;Listening on port 8080&#34;)); EOFThen create a Dockerfile in the same directory:
cat &gt; Dockerfile &lt;&lt;EOF FROM cgr.dev/chainguard/node:latest WORKDIR /app COPY --chown=node:node server.js ./ EXPOSE 8080 CMD [&#34;server.js&#34;] EOFChainguard Containers run as a nonroot user by default — node in this image — so COPY --chown=node:node gives the application access to its own files without switching to root. Because the entrypoint is already node, CMD only needs to name the script.
Build the image:
docker build . --pull -t hello-chainguardUsing the hello-chainguard image, start a container in the background:
docker run -d --name hello-cg -p 8080:8080 hello-chainguardThen send it a request:
curl localhost:8080{&#34;message&#34;:&#34;Hello from a Chainguard Container&#34;,&#34;node&#34;:&#34;v26.6.0&#34;,&#34;uid&#34;:65532}The uid in the response is 65532, confirming that the application runs unprivileged. Stop the container when you&rsquo;re done:
docker rm -f hello-cg Step 3: Use a development variant when you need extra tooling Chainguard&rsquo;s standard containers follow a distroless philosophy: they carry only what the container needs to function. For example, the Node container has no system package manager:
docker run --rm --entrypoint sh cgr.dev/chainguard/node:latest -c &#34;apk --version&#34;sh: apk: not foundThe development variant, tagged latest-dev, adds apk and other utilities for building, testing, and debugging:
docker run --rm --entrypoint sh cgr.dev/chainguard/node:latest-dev -c &#34;apk --version&#34;apk-tools 2.14.10, compiled for x86_64.To keep a small attack surface in production, install dependencies and compile artifacts in the development variant, then copy the results into the standard variant with a multi-stage build. Refer to Development and production container variants for how the variants differ, and to porting a sample application for a multi-stage example.
Step 4: Verify the container and inspect its SBOM Chainguard signs every container it builds, along with the attestations that describe it. Check the signature on the image you pulled:
cosign verify \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ --certificate-identity=https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main \ cgr.dev/chainguard/node | jqCosign confirms that the signature exists in the transparency log and that a trusted certificate authority issued the signing certificate, then prints the signature payload.
Every container also ships with a signed SBOM. Download the SPDX document to see each package in the image:
cosign download attestation \ --platform linux/amd64 \ --predicate-type https://spdx.dev/Document \ cgr.dev/chainguard/node | jq -r &#39;.payload&#39; | base64 -d | jq -r &#39;.predicate&#39;For the rest of the available attestations and the commands that verify them, refer to verifying containers and metadata signatures and retrieving SBOMs and attestations.
Next steps Work through a guide for your own stack: nginx, PostgreSQL, Python, Go, or any other language or service. Move an existing workload over with the migration guides. Learn what a Chainguard Container includes and who patches what in the shared responsibility model and the container categories reference. Understand why these images carry so few vulnerabilities in Chainguard&rsquo;s low-to-no CVE commitment. 
