Bug
Dockerfile.api produces images that crash at startup with:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/app/packages/coredb/dist/schema'
imported from /app/packages/coredb/dist/lib/organization-service-account.js
Root Cause
Two issues in the production runtime:
1. Extensionless ESM imports
@refref/coredb uses "type": "module" and compiles with moduleResolution: "bundler". The compiled JS output has extensionless imports:
// packages/coredb/dist/lib/organization-service-account.js
import { user, orgUser, apikey, org } from "../schema"; // missing .js extension
Node.js ESM strict resolution requires file extensions. The dev server uses tsx which patches resolution, but production uses node dist/index.js which doesn't.
2. Missing non-JS files in runner stage
The runner stage only copies dist/ and package.json from apps/api/, missing openapi.yaml which is read at runtime:
Error: ENOENT: no such file or directory, open '/app/apps/api/openapi.yaml'
Workaround
Use tsx instead of node to run the compiled output:
CMD ["pnpm", "tsx", "dist/index.js"]
And copy the full app directory instead of just dist:
COPY --from=base /app/ ./
Proper Fix Options
- Add
rewriteRelativeImportExtensions: true to tsconfig (TS 5.7+) so compiled output has .js extensions
- Or switch to a bundler (e.g., tsup, esbuild) that produces a single output file with resolved imports
- Copy
openapi.yaml in the Dockerfile runner stage
Environment
- Node.js v24
- TypeScript 5.7+
- pnpm 10.15.0
Bug
Dockerfile.apiproduces images that crash at startup with:Root Cause
Two issues in the production runtime:
1. Extensionless ESM imports
@refref/coredbuses"type": "module"and compiles withmoduleResolution: "bundler". The compiled JS output has extensionless imports:Node.js ESM strict resolution requires file extensions. The dev server uses
tsxwhich patches resolution, but production usesnode dist/index.jswhich doesn't.2. Missing non-JS files in runner stage
The runner stage only copies
dist/andpackage.jsonfromapps/api/, missingopenapi.yamlwhich is read at runtime:Workaround
Use
tsxinstead ofnodeto run the compiled output:And copy the full app directory instead of just dist:
COPY --from=base /app/ ./Proper Fix Options
rewriteRelativeImportExtensions: trueto tsconfig (TS 5.7+) so compiled output has.jsextensionsopenapi.yamlin the Dockerfile runner stageEnvironment