Skip to content

feat(deploy): warn when the Docker build context is unexpectedly large#4943

Open
robgough wants to merge 1 commit into
superfly:masterfrom
robgough:warn-large-build-context
Open

feat(deploy): warn when the Docker build context is unexpectedly large#4943
robgough wants to merge 1 commit into
superfly:masterfrom
robgough:warn-large-build-context

Conversation

@robgough

@robgough robgough commented Jun 25, 2026

Copy link
Copy Markdown

What

fly deploy now prints a warning when the Docker build context it is about to
upload to the builder is unexpectedly large, and lists the largest paths so you
can spot anything that should be in .dockerignore.

Example:

WARN Build context is 1.3 GB across 48,213 files. It is uploaded to the builder on
     every deploy, and a large context can make builds noticeably slower.
     Largest paths in the context:
       .cache/        1.0 GB
       node_modules/  220 MB
       .npm/          93 MB
     If some of these don't need to be in the image, add them to .dockerignore:
     https://docs.docker.com/build/concepts/context/#dockerignore-files
     (disable with --build-context-warn-size 0)

Why

I recently had deploys that were mysteriously slow. The cause turned out to be a
.dockerignore that was missing some large folders (Playwright browsers and
assorted tool caches), so ~1.3 GB of context was being uploaded to the builder
on every deploy before the image build even started. Adding the missing entries
fixed it immediately.

flyctl already walks the working directory and applies .dockerignore to send
the context, so it is well placed to gently point out when a context is far
larger than you probably intended — before you sit through the slow transfer.
Discussion: https://community.fly.io/t/feature-request-warn-or-require-an-override-when-the-docker-build-context-is-unexpectedly-large/28163

How

  • New internal/build/imgsrc/context_size.go walks the build context applying
    the same .dockerignore rules used when building (including parent-dir matches
    and negated re-includes, mirroring docker/pkg/archive), and sums the largest
    top-level paths. It only stats files (never reads them) and prunes ignored
    directories, so the cost is bounded by the context it is warning about.
  • Resolver.BuildImage calls it once, up front, for Dockerfile builds.
  • Adds a --build-context-warn-size flag (also settable via
    FLY_BUILD_CONTEXT_WARN_SIZE) on every command that builds from a Dockerfile —
    deploy, launch, machine run, machine update, console — so the warning
    can be tuned or turned off (--build-context-warn-size 0). It follows the
    existing *-size flag convention (swap-size, rootfs-size, …): a String
    parsed with helpers.ParseSize, accepting a plain number (MB) or a
    human-readable size like 512mb/1gb.

Design notes / things I'd love feedback on:

  • Non-blocking and best-effort. It only ever prints a warning; any error
    (unreadable dir, etc.) silently skips the check so a deploy is never blocked or
    meaningfully slowed by it. The thread floated optionally requiring an
    override — happy to add a stricter mode, but a warning felt like the right
    default to start with.
  • Threshold. Defaults to 100 MB, tunable per build with
    --build-context-warn-size or globally with FLY_BUILD_CONTEXT_WARN_SIZE, and
    disabled by setting either to 0. I'm genuinely unsure 100 MB is the right
    number — I took it from the figure in the thread, but folks who've seen far
    more app setups than I have will have a much better sense of what counts as
    "normal" versus genuinely surprising. The main thing I want to avoid is the
    warning firing so often on legitimately-sized contexts that people reflexively
    set it to 0 and forget about it — at which point it's worse than useless. So
    I'd lean towards erring high if in doubt, and I'd really value your read on a
    sensible default (or a smarter heuristic than a flat byte count).
  • Scope. Limited to plain Dockerfile builds, which are the ones that upload a
    .dockerignore-filtered context. Buildpacks/builtins/custom builders manage
    their own context and are skipped. Could be extended later.

Testing

  • Unit tests in internal/build/imgsrc/context_size_test.go cover the size
    totals, largest-path ordering, .dockerignore exclusion, nested-directory
    aggregation, negated re-includes, and flag/env threshold precedence.
  • go test ./internal/build/imgsrc/... and golangci-lint run both pass.

Large build contexts are uploaded to the builder on every deploy before the
image build starts, so an accidental omission from .dockerignore (a cache or
tooling directory) can silently make deploys much slower.

flyctl already walks the working directory and applies .dockerignore to build
the context, so this adds a cheap, stat-only pass over the same files that warns
when the context exceeds a threshold and lists the largest paths. The threshold
defaults to 100 MB and is tunable per build with --build-context-warn-size or
globally with FLY_BUILD_CONTEXT_WARN_SIZE (0 disables). Best-effort: it never
blocks a deploy.

https://community.fly.io/t/feature-request-warn-or-require-an-override-when-the-docker-build-context-is-unexpectedly-large/28163
@robgough robgough marked this pull request as ready for review June 25, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant