4.2.5.2 RUN Dependency Download
A focused guide to RUN Dependency Download, connecting core concepts with practical Docker and container operations.
Using RUN for dependency downloads covers the pattern of invoking a language ecosystem's dependency manager — npm, pip, Maven, Go modules — through a RUN instruction to retrieve and install an application's declared dependencies as part of the image build.
A Typical Dependency Download Step
After copying a dependency manifest into the build context, a RUN instruction invokes the appropriate tool to resolve and download everything the manifest declares.
COPY package.json package-lock.json ./
RUN npm ci
Using npm ci rather than npm install ensures dependencies are installed strictly according to the lockfile, rather than allowing the package manager to resolve to newer, potentially different versions.
Downloading Go Modules
Go's module system similarly downloads dependencies based on a manifest, and can be run as a separate, cacheable step before the rest of the source code is copied in.
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o app .
Downloading Maven Dependencies
Java projects using Maven can similarly resolve dependencies ahead of compiling the actual application source, taking advantage of the same caching benefit.
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src/ ./src/
RUN mvn package
Avoiding Repeated Downloads Across Builds
Because dependency downloads can be time-consuming, structuring the Dockerfile so this step is cached separately from application source changes — as shown in each example above — avoids re-downloading dependencies on every single build.
docker build -t myapp .
echo "// change" >> main.go
docker build -t myapp .
The second build reuses the cached dependency download layer entirely, since only the application source, copied afterward, actually changed.
Why This Pattern Matters
Treating dependency download as its own distinct, cacheable RUN step, separated from application source by careful instruction ordering, is one of the most broadly applicable techniques for keeping everyday build times manageable across virtually every language ecosystem.