.dockerignore excludes tsconfig.json, tsconfig.build.json, and nest-cli.json (under "Documentation and configs not needed in production container"). These are not docs — nest build (and nest start) requires all three to know how to compile/run the TypeScript project.
Reproduced directly (not just inferred from reading the files): I built a copy of this repo's build context filtered through the exact .dockerignore patterns (rsync --exclude-from=.dockerignore), ran npm ci inside it, then npm run build:
> mergefi-backend@0.0.1 build
> nest build
Error Could not find TypeScript configuration file "tsconfig.json". Please, ensure
that you are running this command in the appropriate directory (inside Nest workspace).
Concretely, this breaks:
docker build --target runner -t mergefi-backend:latest . — the exact command README.md's "Production Builds & Security" section documents as how to build the production image. The builder stage's RUN npm run build executes during the image build (no bind mount exists at build time to paper over the gap), so this command fails outright, every time, for anyone who runs it.
- A standalone
docker build --target development + docker run (without docker compose) — the development stage's CMD ["npm", "run", "start:dev"] runs nest start --watch, which has the same nest-cli.json/tsconfig.json dependency.
The one path that appears to work is docker compose up --build for local dev — but only by coincidence: docker-compose.yml's app service bind-mounts the entire host repo (.:/usr/src/app) over the container's /usr/src/app at container start, which happens after the image build completes and masks the incomplete COPY . . by overlaying the real host files (including tsconfig.json) before npm run start:dev actually executes. The moment someone builds/runs the runner/production target directly — exactly what the README documents — there's no bind mount to save it.
This has presumably gone unnoticed because .github/workflows/ci.yml never builds the Docker image at all (CI's own "Build Application" step runs npm run build directly against the full checked-out repo, which does have tsconfig.json, so it can't catch a .dockerignore-specific failure).
Fix: remove tsconfig.json, tsconfig.build.json, and nest-cli.json from .dockerignore (they're small text files with no secrets in them — there's no reason to exclude them from the build context).
.dockerignoreexcludestsconfig.json,tsconfig.build.json, andnest-cli.json(under "Documentation and configs not needed in production container"). These are not docs —nest build(andnest start) requires all three to know how to compile/run the TypeScript project.Reproduced directly (not just inferred from reading the files): I built a copy of this repo's build context filtered through the exact
.dockerignorepatterns (rsync --exclude-from=.dockerignore), rannpm ciinside it, thennpm run build:Concretely, this breaks:
docker build --target runner -t mergefi-backend:latest .— the exact command README.md's "Production Builds & Security" section documents as how to build the production image. Thebuilderstage'sRUN npm run buildexecutes during the image build (no bind mount exists at build time to paper over the gap), so this command fails outright, every time, for anyone who runs it.docker build --target development+docker run(withoutdocker compose) — thedevelopmentstage'sCMD ["npm", "run", "start:dev"]runsnest start --watch, which has the samenest-cli.json/tsconfig.jsondependency.The one path that appears to work is
docker compose up --buildfor local dev — but only by coincidence:docker-compose.yml'sappservice bind-mounts the entire host repo (.:/usr/src/app) over the container's/usr/src/appat container start, which happens after the image build completes and masks the incompleteCOPY . .by overlaying the real host files (includingtsconfig.json) beforenpm run start:devactually executes. The moment someone builds/runs therunner/production target directly — exactly what the README documents — there's no bind mount to save it.This has presumably gone unnoticed because
.github/workflows/ci.ymlnever builds the Docker image at all (CI's own "Build Application" step runsnpm run builddirectly against the full checked-out repo, which does havetsconfig.json, so it can't catch a.dockerignore-specific failure).Fix: remove
tsconfig.json,tsconfig.build.json, andnest-cli.jsonfrom.dockerignore(they're small text files with no secrets in them — there's no reason to exclude them from the build context).