Make cache mounts predictable for multi-stage Docker builds

Make cache mounts predictable for multi-stage Docker builds

calendar_today ago • schedule2 min read
— Originally published at chriseugenerodriguez.com

Prerequisites

  • Basic Dockerfile multi-stage knowledge (build stages, COPY, RUN)
  • Familiarity with your package manager’s cache path (npm, Yarn, pip, etc.)

Implementation decision

Use a small configuration helper that enforces Docker’s documented options for RUN --mount=type=cache and keeps a predictable default: the mount id defaults to the target path. The helper validates that target is an absolute path composed of safe characters, that an explicit id is a non-empty safe string, and that sharing is one of Docker's documented modes (shared, private, locked). Format the mount fragment exactly so you paste a single, well-formed --mount flag into the dependency-install step.

Expected result

  • The dependency-install step receives a mount attached to the package manager’s real cache directory, which reduces repeated download time when the builder preserves local storage between runs.
  • The default id equal to the target path keeps cache identity readable and stable across stages. If you need separate namespaces, supply an explicit id to avoid collisions.
  • Use sharing=locked when your package manager requires exclusive access to cache files; it prevents concurrent writers from corrupting shared caches on shared CI runners.

One limitation

Cache mounts persist in the builder's local storage only. If your CI spins up a fresh builder for every job or the builder evicts local cache storage, the mount will be empty at each run. In that case, address persistence at the CI/builder layer (external caches, preserved builder instances, or cache export/import) rather than by changing the Dockerfile mount syntax.

(The server will insert the verified implementation example as a fenced code block in place of the demonstration.)

Working example

const SHARING_VALUES = new Set(['shared', 'private', 'locked']);
const SAFE_COMPONENT = /^[A-Za-z0-9_./-]+$/;

export function validateCacheMountInput({ target, id, sharing = 'shared' } = {}) {
  if (typeof target !== 'string' || target.length === 0) {
    throw new TypeError('target must be a non-empty string');
  }
  if (!target.startsWith('/')) {
    throw new RangeError('target must be an absolute path');
  }
  if (!SAFE_COMPONENT.test(target)) {
    throw new RangeError('target must contain only letters, digits, slash, dot, underscore or hyphen');
  }

  if (id !== undefined) {
    if (typeof id !== 'string' || id.length === 0) {
      throw new TypeError('id must be a non-empty string when provided');
    }
    if (!SAFE_COMPONENT.test(id)) {
      throw new RangeError('id must contain only letters, digits, slash, dot, underscore or hyphen');
    }
  }

  if (!SHARING_VALUES.has(sharing)) {
    throw new RangeError('sharing must be one of shared, private, locked');
  }
}

export function buildCacheMountOptions({ target, id, sharing = 'shared' } = {}) {
  validateCacheMountInput({ target, id, sharing });
  return { type: 'cache', target, id: id ?? target, sharing };
}

export function formatRunMount(options) {
  const { type, target, id, sharing } = buildCacheMountOptions(options);
  return `--mount=type=${type},target=${target},id=${id},sharing=${sharing}`;
}

Read the full article: https://chriseugenerodriguez.com/blog/reuse-cache-mounts-multi-stage-dockerfiles

🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

Cache-Control Headers for Web Performance: CDN and Browser Caching That Sticks

ApogeeWatcherverified - Sep 17

Three Design-to-Code Rules Most Developers Ignore (That Will Make You a Better Engineer)

Joemetry - Sep 26

My 30-day log cleanup kept a file that was 30 and a half days old

BashSnippets - Oct 8

Optimizing the Clinical Interface: Data Management for Efficient Medical Outcomes

Huifer - Jan 26

Faceted Navigation and Pagination for Ecommerce SEO

floxolab - Aug 31
chevron_left
219 Points • 8 Badges
Santa Monica, CA • chriseugenerodriguez.com
5Posts
0Comments
1Connections
10 years fe

Related Jobs

Commenters (This Week)

1 comment
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!