Skip to content

API and gateway runtime images ship the full Node build image with gcc, git and turbo, tripling their size #1794

Open

Description

@joshunrau

The api and gateway runtime images are built from their build stage, base. That stage is the full node:lts-krypton image plus corepack and a global turbo install, and none of it is needed to run node ./dist/…. Both apps are already bundled into dist/, and the runner stage copies only dist/ and a few generated files out of the installer. The runtime still carries the full Debian toolchain from the base image: gcc, g++, make, python3, git, svn, ssh, curl and wget. It also carries pnpm (through corepack) and turbo@2.11.5 under /pnpm. As a result, every deployment and every upgrade downloads about three times more than the app needs, and anyone who gains code execution in either container has a compiler, git and network tools at hand. The gateway is the internet-facing one.

Where

apps/api/Dockerfile:1-8 and :25-26 (the gateway Dockerfile has the same structure, apps/gateway/Dockerfile:1-9 and :27):

FROM node:lts-krypton AS base
# ...
RUN corepack enable
RUN pnpm install -g turbo@2.11.5
# ...
# RUN SERVER
FROM base AS runner
COPY --from=installer /app/apps/api/dist/ /app/dist/

Reproduce

  1. Run docker manifest inspect --verbose ghcr.io/douglasneuroinformatics/open-data-capture-api:latest and sum the linux/amd64 layer sizes. Do the same for node:lts-krypton and node:24-slim.
  2. Run docker run --rm --entrypoint sh ghcr.io/douglasneuroinformatics/open-data-capture-api:latest -c 'for b in gcc git make python3 turbo pnpm; do command -v $b; done'.

Actual: the api image is 488.1 MB compressed (gateway: 487.7 MB), and 411.9 MB of that is the node:lts-krypton base. node:24-slim, the same Node 24 on the same Debian 12, is 80.8 MB, so a slim runtime would come to roughly 160 MB. Step 2 prints /usr/bin/gcc, /usr/bin/git, /usr/bin/make, /usr/bin/python3, /pnpm/bin/turbo and /usr/local/bin/pnpm.
Expected: the runtime stage contains Node, the bundled app and the shared libraries it loads, and no build tooling.

Tests

The e2e suite does not use the images, so no unit or Playwright test applies. Verify the fix in the built images. docker compose up -d should bring up a working stack, including login, a recorded instrument and a completed remote assignment, which exercises Prisma in both containers. The step 2 loop should print nothing, and the compressed size should drop accordingly.

Suggested fix

Give each runner its own FROM node:24-slim (or the matching krypton slim tag) instead of FROM base, and move ENV NODE_OPTIONS and the corepack and turbo setup so they apply to the build stages only. node:24-slim ships without libssl, which Prisma's query engine loads, so add RUN apt-get update && apt-get install -y --no-install-recommends openssl && rm -rf /var/lib/apt/lists/* to the runner. Keep USER node in the api runner. The gateway running as root is tracked separately in #1792.

Activity

  1. added
    Priority: LowNice to have, cosmetic or speculative
    EnhancementType: an improvement to an existing feature, including performance
    Difficulty: MediumStraightforward change, about a day or less
    Area: InfrastructureDeployment, Docker, CI, logging, CLIs, build and test tooling
    PerformanceSpeed, memory or scalability
    SecurityAuthentication, authorization, data exposure or a vulnerable dependency
    on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: InfrastructureDeployment, Docker, CI, logging, CLIs, build and test toolingDifficulty: MediumStraightforward change, about a day or lessEnhancementType: an improvement to an existing feature, including performancePerformanceSpeed, memory or scalabilityPriority: LowNice to have, cosmetic or speculativeSecurityAuthentication, authorization, data exposure or a vulnerable dependency

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions