Skip to main content

Documentation Index

Fetch the complete documentation index at: https://tally.wharflab.com/llms.txt

Use this file to discover all available pages before exploring further.

bundle install doesn’t use a BuildKit cache mount on ${BUNDLE_PATH}/cache.
PropertyValue
SeverityInfo (default) / Warning (project has native-extension gems)
CategoryPerformance
DefaultEnabled
Auto-fixYes (FixSuggestion, no-edit)

Description

BuildKit’s RUN --mount=type=cache,target=${BUNDLE_PATH}/cache keeps the gem-extraction cache across builds. Without it, every cache-busted bundle install re-fetches and (for native-extension gems) recompiles every gem from scratch — typically 30s+ on a non-trivial Rails project, and minutes for nokogiri-heavy or grpc-heavy projects. The corpus shows only 7 of 196 Dockerfiles use cache mounts at all. This rule fires when:
  • The Dockerfile carries the # syntax=docker/dockerfile:1 (or higher) pragma — without it, --mount=type=cache errors at build time.
  • A Ruby-shaped stage runs bundle install.
  • That RUN doesn’t carry a --mount=type=cache,target=... whose target matches the Bundler cache directory.
Recognized cache-target paths:
  • ${BUNDLE_PATH}/cache (variable form, what the Rails generator template uses).
  • /usr/local/bundle/cache (Rails generator’s default BUNDLE_PATH).
  • /bundle/cache, /bundle-cache, /cache (other commonly-seen layouts).

Context-aware refinement

When tally is invoked with --context and Gemfile.lock is observable, severity escalates from info to warning for projects with at least one native-extension gem (nokogiri, pg, mysql2, sqlite3, grpc, ffi, oj, bcrypt, nio4r, puma, rugged, protobuf, sassc, eventmachine, unf_ext, racc, bigdecimal). The rebuild-from-scratch cost of these gems is exactly what the cache mount fixes.

Examples

Before

# syntax=docker/dockerfile:1
FROM ruby:3.3-slim
COPY Gemfile Gemfile.lock ./
RUN bundle install

After

# syntax=docker/dockerfile:1
FROM ruby:3.3-slim
COPY Gemfile Gemfile.lock ./
RUN --mount=type=cache,id=bundler,target=${BUNDLE_PATH}/cache,sharing=locked \
    bundle install
The id=bundler makes the cache reusable across Dockerfiles. The sharing=locked prevents corruption when concurrent builds touch the same cache.

Auto-fix

FixSuggestion. The rule emits a non-edit suggestion: rewriting --mount=type=cache onto multi-line RUN chains is too easy to get wrong (continuation backslashes, existing --mount flags, heredoc bodies). The user applies the suggestion manually.

References