node_modules with bind mounts in Docker
Docker was created to isolate your development environment to suppress any possible issues with different local OSes and configurations. So the idea is that everything is acting the same on every platform. The problems may arise when you run npm i
locally and some packages has to be built depending on your system architecture. We want to avoid it and run npm i
always in the container.
I will use a simple Node
image in this example
FROM node:12.16-slim WORKDIR /app COPY package.json package-lock*.json ./ RUN npm install && npm cache clean --force COPY . . CMD ["node", "index.js"]
version: '2.4' services: express: build: . ports: - 3000:3000 volumes: - .:/app
Never use npm i
on host
If you do not have installed node_modules
, you can’t docker compose up
until you’ve used docker-compose run npm i
. Although it is installed in container, there is mapping .:/app
in docker-compose
file, so it will be visible from host file system. In case you are using MacOS
and in container is Ubuntu
or some other OS different than MacOS
– those files will me compiled as a source to different architecture. Your app will running ok in a container, but we want to avoid to keep node_modules
separate, in case of any doubts that may arise some day, why app is not working as we want.
Another issue may be, when you do npm i
on your host, then run docker-compose up
and your project probably will be running… until it’s not. It’s analogous to previous example, but this time, we compile some modules on MacOS
and bind it to the container, when Ubuntu
is running.
Move node_modules
in the image to hide it from host
There is feature, which tells that Node
will look for node_modules
in upper directory directory if it does not find it in current one. We are going to use this here. So, edit the Dockerfile
FROM node:12.16-slim #add parent directory WORKDIR /node COPY package.json package-lock*.json ./ # install dependencies in /node RUN npm install && npm cache clean --force # added new workdir for source files # node_modules will be in parent folder, # hence it will be not visible from host file system WORKDIR /node/app COPY . . CMD ["node", "index.js"]
Then, in docker-compose.yaml
version: '2.4' services: express: build: . ports: - 3000:3000 volumes: # app will be now in subdirectory - .:/node/app # create anonymous volume # map node_modules from host to essentially nothing - /app/node_modules