Docker
Containers
Precompiled Assets
DevOps
Software Deployment

Sharing precompiled assets across docker containers

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

If multiple containers need the same compiled frontend bundle, binary, or generated static files, the best sharing strategy depends on when the assets are produced. In Docker, the cleanest pattern is usually to share them through image layers at build time, not by copying files between already running containers.

Best Option: Build Once, Copy Through a Multi-Stage Dockerfile

When the assets are part of the application release, use a multi-stage build. One stage compiles the assets, and later stages copy the results.

dockerfile
1FROM node:20 AS assets
2WORKDIR /app
3
4COPY package.json package-lock.json ./
5RUN npm ci
6
7COPY . .
8RUN npm run build
9
10FROM nginx:alpine
11COPY --from=assets /app/dist /usr/share/nginx/html

This is usually better than sharing files between live containers because:

  • the final image is self-contained
  • Docker layer caching speeds up rebuilds
  • deployment becomes repeatable
  • there is no runtime dependency on another container's filesystem

If several services need the same compiled output, you can also create a dedicated asset image and copy from it in downstream Dockerfiles.

Shared Asset Image Pattern

For example, build one image whose only purpose is to hold compiled artifacts:

dockerfile
1FROM node:20 AS build
2WORKDIR /app
3
4COPY package.json package-lock.json ./
5RUN npm ci
6COPY . .
7RUN npm run build
8
9FROM scratch
10COPY --from=build /app/dist /dist

Then another image can consume those assets during its own build:

dockerfile
FROM nginx:alpine
COPY --from=myorg/shared-assets:latest /dist /usr/share/nginx/html

This works well when several final images need the same build output but should remain independently runnable.

When a Volume Makes Sense

Volumes are more appropriate in development workflows, especially when one container builds assets and another serves them.

yaml
1services:
2  builder:
3    image: node:20
4    working_dir: /app
5    volumes:
6      - assets:/app/dist
7      - .:/app
8    command: sh -c "npm ci && npm run build"
9
10  web:
11    image: nginx:alpine
12    volumes:
13      - assets:/usr/share/nginx/html:ro
14
15volumes:
16  assets:

This can be useful locally, but it is not usually the best production pattern. Runtime-shared volumes introduce ordering concerns, extra moving parts, and the need to coordinate asset freshness.

Why Copying Between Running Containers Is Usually Wrong

Docker containers are meant to be replaceable. If container B depends on files manually copied from container A after startup, you are building an implicit deployment pipeline out of mutable runtime state.

That creates several problems:

  • new containers start empty unless the copy step runs again
  • scaling becomes awkward because state is no longer image-defined
  • debugging gets harder because containers are no longer identical

If the assets are part of the release artifact, they belong in the image build process.

Choose Based on Lifecycle

The right question is not "how do I share files" but "when are these files produced and how stable are they?"

  • If assets are release artifacts, bake them into images.
  • If assets are generated during local iteration, a shared volume can be acceptable.
  • If multiple services consume the same static output, consider a dedicated asset image or one upstream build stage.

That framing prevents a lot of Docker anti-patterns.

Common Pitfalls

The biggest pitfall is treating containers like virtual machines and trying to maintain shared mutable folders between them in production. That usually fights Docker's strengths instead of using them.

Another issue is putting the build toolchain in every final runtime image just so assets can be compiled repeatedly. Multi-stage builds are cleaner and produce smaller runtime images.

Developers also sometimes use a shared volume without defining which container owns the build step. That leads to race conditions and stale assets.

Finally, be careful with cache invalidation. If the asset source changes but the build stage inputs are copied too broadly or too narrowly, Docker caching can hide stale outputs until later.

Summary

  • The cleanest way to share precompiled assets is usually through image builds, not runtime copying.
  • Multi-stage Dockerfiles are the default best pattern for release assets.
  • A dedicated asset image works when several downstream images need the same compiled files.
  • Shared volumes are reasonable mainly for development workflows where one container builds and another consumes.
  • Prefer immutable images over mutable cross-container filesystem sharing in production.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.