skip to Main Content

I’m trying to set up a multi-stage Docker build for my Node.js and Nest.js application. The Dockerfile includes installing dependencies, building the application, and running it. However, I’m encountering an issue with the npm run build command in the production stage of the Dockerfile.

Here’s a simplified version of my Dockerfile:

# Use node base image with tag 18-slim
FROM node:18-slim as base

# Set NODE_ENV environment variable to production
ENV NODE_ENV=production

# Expose port 3000
EXPOSE 3000

# Create app directory and set permissions
WORKDIR /app
RUN chown -R node:node /app

# Switch to non-root user
USER node

# Copy package.json and package-lock.json
COPY --chown=node:node package*.json ./

# Install dependencies
RUN npm ci && npm cache clean --force

# Set PATH environment variable in dev stage
ENV PATH /app/node_modules/.bin:$PATH

# Copy source code
COPY --chown=node:node . .

# Development stage
FROM base as dev

# Set NODE_ENV environment variable to development
ENV NODE_ENV=development

# Command to run development server
CMD ["npm", "run", "start:dev"]

# Production stage
FROM base as prod

# Build production code
RUN npm run build

# Command to run production server
CMD ["node", "dist/main.js"]

The error message I’m getting is:

sh: 1: nest: not found

It seems that the Nest.js CLI is not available in the PATH during the production build, even though it’s installed as a dev dependency in my package.json.

#11 [prod 1/2] RUN ls /app/node_modules/.bin
#11 0.152 acorn
#11 0.152 color-support
#11 0.152 highlight
#11 0.152 js-yaml
#11 0.152 mime
#11 0.152 mkdirp
#11 0.152 node-pre-gyp
#11 0.152 nopt
#11 0.152 opencollective
#11 0.152 semver
#11 0.152 sha.js
#11 0.152 ts-node
#11 0.152 ts-node-cwd
#11 0.152 ts-node-esm
#11 0.152 ts-node-script
#11 0.152 ts-node-transpile-only
#11 0.152 ts-script
#11 0.152 tsc
#11 0.152 tsserver
#11 0.152 typeorm
#11 0.152 typeorm-ts-node-commonjs
#11 0.152 typeorm-ts-node-esm
#11 0.152 uuid
#11 DONE 0.2s

How can I ensure that the Nest.js CLI is available in the PATH during the production build in my Dockerfile?

2

Answers


  1. Rev2

    The following instruction in base stage renders /app/node_modules/.bin/nest unavailable.

    # Set NODE_ENV environment variable to production
    ENV NODE_ENV=production
    

    But in the current configuration of Dockerfile, because base stage is meant for both dev and prod, including dev dependencies will not sit well for prod stage.

    Now, I suggest the following to remedy the situation:

    • Remove ENV NODE_ENV=production and RUN npm ci from base stage, making this stage free from preparing dev/prod dependencies.
    • Put ENV NODE_ENV=development and RUN npm ci to dev stage.
    • Put ENV NODE_ENV=production and RUN npm ci to prod stage.

    Docker has a nice Dockerfile example on this matter.

    https://docs.docker.com/language/nodejs/develop/#update-your-dockerfile-for-development

    Rev1

    See if changing /dev/node_modules/.bin to /app/node_modules/.bin resolves the issue.


    At base stage, instruction WORKDIR /app set the working directory for the following instructions like RUN to be performed at /app, so that following
    instruction RUN npm install creates /app/node_modules.

    But later on, at dev and prod stage, instructions ENV PATH include a path /dev/node_modules/.bin, which contradicts the setup in base stage.

    Login or Signup to reply.
  2. Not sure what your project layout looks like, but suppose that it’s simple like this:

    ├── Dockerfile
    ├── package.json
    ├── package-lock.json
    ├── src
    │   └── index.js
    └── webpack.config.js
    

    The following will work and has minimal changes relative to your current setup.

    🗎 Dockerfile

    FROM node:18-slim as base
    
    ENV NODE_ENV=production
    
    EXPOSE 3000
    
    WORKDIR /app
    RUN chown -R node:node /app
    
    USER node
    
    COPY --chown=node:node package*.json ./
    
    RUN npm ci && npm cache clean --force
    
    ENV PATH /app/node_modules/.bin:$PATH
    
    COPY --chown=node:node . .
    
    # STAGE: DEV ------------------------------------------------------------------
    
    FROM base as dev
    
    ENV NODE_ENV=development
    
    CMD ["npm", "run", "start:dev"]
    
    # STAGE: prod -----------------------------------------------------------------
    
    FROM base as prod
    
    RUN npm run build
    
    CMD ["node", "dist/main.js"]
    

    🗎 package.json

    {
        "name": "application-name",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "start": "node dist/main.js",
          "start:dev": "nodemon src/index.js",
          "build": "webpack"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "dependencies": {
          "express": "^4.17.1",
          "@nestjs/cli": "10.3.2",
          "webpack-cli": "5.1.4"
        },
        "devDependencies": {
          "nodemon": "^2.0.7"
        }
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search