How to cache the RUN npm install instruction when docker build a Dockerfile





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







54















I am currently developing a Node backend for my application.
When dockerizing it (docker build .) the longest phase is the RUN npm install. The RUN npm install instruction runes on every small server code change, impacting the productivity by making the developer wait for the build to finish each time.



I found that running npm install where the application code lives and adding the node_modules to the container with the ADD instruction solves this issue,
but it is far from best practice. It kind of breaks the whole idea of dockerizing it and it cause the container to weight much more.



Any other solution?










share|improve this question































    54















    I am currently developing a Node backend for my application.
    When dockerizing it (docker build .) the longest phase is the RUN npm install. The RUN npm install instruction runes on every small server code change, impacting the productivity by making the developer wait for the build to finish each time.



    I found that running npm install where the application code lives and adding the node_modules to the container with the ADD instruction solves this issue,
    but it is far from best practice. It kind of breaks the whole idea of dockerizing it and it cause the container to weight much more.



    Any other solution?










    share|improve this question



























      54












      54








      54


      21






      I am currently developing a Node backend for my application.
      When dockerizing it (docker build .) the longest phase is the RUN npm install. The RUN npm install instruction runes on every small server code change, impacting the productivity by making the developer wait for the build to finish each time.



      I found that running npm install where the application code lives and adding the node_modules to the container with the ADD instruction solves this issue,
      but it is far from best practice. It kind of breaks the whole idea of dockerizing it and it cause the container to weight much more.



      Any other solution?










      share|improve this question
















      I am currently developing a Node backend for my application.
      When dockerizing it (docker build .) the longest phase is the RUN npm install. The RUN npm install instruction runes on every small server code change, impacting the productivity by making the developer wait for the build to finish each time.



      I found that running npm install where the application code lives and adding the node_modules to the container with the ADD instruction solves this issue,
      but it is far from best practice. It kind of breaks the whole idea of dockerizing it and it cause the container to weight much more.



      Any other solution?







      node.js docker dockerfile






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 3 '16 at 14:22







      ohadgk

















      asked Mar 3 '16 at 14:19









      ohadgkohadgk

      1,2581610




      1,2581610
























          5 Answers
          5






          active

          oldest

          votes


















          92














          Ok so I found this great article about efficiency when writing a docker file.



          This is an example of a bad docker file adding the application code before running the RUN npm install instruction:



          FROM ubuntu

          RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
          RUN apt-get update
          RUN apt-get -y install python-software-properties git build-essential
          RUN add-apt-repository -y ppa:chris-lea/node.js
          RUN apt-get update
          RUN apt-get -y install nodejs

          WORKDIR /opt/app

          COPY . /opt/app
          RUN npm install
          EXPOSE 3001

          CMD ["node", "server.js"]


          By dividing the copy of the application into 2 COPY instructions (one for the package.json file and the other for the rest of the files) and running the npm install instruction before adding the actual code, any code change wont trigger the RUN npm install instruction, only changes of the package.json will trigger it. Better practice docker file:



          FROM ubuntu
          MAINTAINER David Weinstein <david@bitjudo.com>

          # install our dependencies and nodejs
          RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
          RUN apt-get update
          RUN apt-get -y install python-software-properties git build-essential
          RUN add-apt-repository -y ppa:chris-lea/node.js
          RUN apt-get update
          RUN apt-get -y install nodejs

          # use changes to package.json to force Docker not to use the cache
          # when we change our application's nodejs dependencies:
          COPY package.json /tmp/package.json
          RUN cd /tmp && npm install
          RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

          # From here we load our application's code in, therefore the previous docker
          # "layer" thats been cached will be used if possible
          WORKDIR /opt/app
          COPY . /opt/app

          EXPOSE 3000

          CMD ["node", "server.js"]


          This is where the package.json file added, install its dependencies and copy them into the container WORKDIR, where the app lives:



          ADD package.json /tmp/package.json
          RUN cd /tmp && npm install
          RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/


          To avoid the npm install phase on every docker build just copy those lines and change the ^/opt/app^ to the location your app lives inside the container.






          share|improve this answer





















          • 2





            That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

            – eljefedelrodeodeljefe
            Jun 3 '16 at 3:15






          • 2





            Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

            – Symmetric
            Jul 28 '16 at 17:24











          • For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

            – Marian Klühspies
            Feb 20 '17 at 11:20






          • 1





            The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

            – J. Fritz Barnes
            Apr 3 '17 at 16:46






          • 17





            I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

            – joniba
            May 31 '17 at 16:57



















          19














          Weird! No one mentions multi-stage build.



          # ---- Base Node ----
          FROM alpine:3.5 AS base
          # install node
          RUN apk add --no-cache nodejs-current tini
          # set working directory
          WORKDIR /root/chat
          # Set tini as entrypoint
          ENTRYPOINT ["/sbin/tini", "--"]
          # copy project file
          COPY package.json .

          #
          # ---- Dependencies ----
          FROM base AS dependencies
          # install node packages
          RUN npm set progress=false && npm config set depth 0
          RUN npm install --only=production
          # copy production node_modules aside
          RUN cp -R node_modules prod_node_modules
          # install ALL node_modules, including 'devDependencies'
          RUN npm install

          #
          # ---- Test ----
          # run linters, setup and tests
          FROM dependencies AS test
          COPY . .
          RUN npm run lint && npm run setup && npm run test

          #
          # ---- Release ----
          FROM base AS release
          # copy production node_modules
          COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
          # copy app sources
          COPY . .
          # expose port and define CMD
          EXPOSE 5000
          CMD npm run start


          Awesome tuto here: https://codefresh.io/docker-tutorial/node_docker_multistage/






          share|improve this answer































            15














            I've found that the simplest approach is to leverage Docker's copy semantics:




            The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .




            This means that if you first explicitly copy the package.json file and then run the npm install step that it can be cached and then you can copy the rest of the source directory. If the package.json file has changed, then that will be new and it will re-run the npm install caching that for future builds.



            A snippet from the end of a Dockerfile would look like:



            # install node modules
            WORKDIR /usr/app
            COPY package.json /usr/app/package.json
            RUN npm install

            # install application
            COPY . /usr/app





            share|improve this answer





















            • 3





              Instead of cd /usr/app you can/should use WORKDIR /usr/app.

              – Vladimir Vukanac
              Jan 17 at 15:53











            • @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

              – J. Fritz Barnes
              Jan 25 at 15:17











            • is npm install run in /usr/app directory or . ?

              – user557657
              Feb 1 at 19:06






            • 1





              @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

              – J. Fritz Barnes
              Feb 7 at 14:35











            • @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

              – user557657
              Feb 8 at 15:20



















            5














            I imagine you may already know, but you could include a .dockerignore file in the same folder containing



            node_modules
            npm-debug.log


            to avoid bloating your image when you push to docker hub






            share|improve this answer































              0














              you don't need to use tmp folder, just copy package.json to your container's application folder, do some install work and copy all files later.



              COPY app/package.json /opt/app/package.json
              RUN cd /opt/app && npm install
              COPY app /opt/app





              share|improve this answer
























              • so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                – user557657
                Feb 1 at 19:19












              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f35774714%2fhow-to-cache-the-run-npm-install-instruction-when-docker-build-a-dockerfile%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              5 Answers
              5






              active

              oldest

              votes








              5 Answers
              5






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              92














              Ok so I found this great article about efficiency when writing a docker file.



              This is an example of a bad docker file adding the application code before running the RUN npm install instruction:



              FROM ubuntu

              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              WORKDIR /opt/app

              COPY . /opt/app
              RUN npm install
              EXPOSE 3001

              CMD ["node", "server.js"]


              By dividing the copy of the application into 2 COPY instructions (one for the package.json file and the other for the rest of the files) and running the npm install instruction before adding the actual code, any code change wont trigger the RUN npm install instruction, only changes of the package.json will trigger it. Better practice docker file:



              FROM ubuntu
              MAINTAINER David Weinstein <david@bitjudo.com>

              # install our dependencies and nodejs
              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              # use changes to package.json to force Docker not to use the cache
              # when we change our application's nodejs dependencies:
              COPY package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

              # From here we load our application's code in, therefore the previous docker
              # "layer" thats been cached will be used if possible
              WORKDIR /opt/app
              COPY . /opt/app

              EXPOSE 3000

              CMD ["node", "server.js"]


              This is where the package.json file added, install its dependencies and copy them into the container WORKDIR, where the app lives:



              ADD package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/


              To avoid the npm install phase on every docker build just copy those lines and change the ^/opt/app^ to the location your app lives inside the container.






              share|improve this answer





















              • 2





                That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

                – eljefedelrodeodeljefe
                Jun 3 '16 at 3:15






              • 2





                Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

                – Symmetric
                Jul 28 '16 at 17:24











              • For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

                – Marian Klühspies
                Feb 20 '17 at 11:20






              • 1





                The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

                – J. Fritz Barnes
                Apr 3 '17 at 16:46






              • 17





                I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

                – joniba
                May 31 '17 at 16:57
















              92














              Ok so I found this great article about efficiency when writing a docker file.



              This is an example of a bad docker file adding the application code before running the RUN npm install instruction:



              FROM ubuntu

              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              WORKDIR /opt/app

              COPY . /opt/app
              RUN npm install
              EXPOSE 3001

              CMD ["node", "server.js"]


              By dividing the copy of the application into 2 COPY instructions (one for the package.json file and the other for the rest of the files) and running the npm install instruction before adding the actual code, any code change wont trigger the RUN npm install instruction, only changes of the package.json will trigger it. Better practice docker file:



              FROM ubuntu
              MAINTAINER David Weinstein <david@bitjudo.com>

              # install our dependencies and nodejs
              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              # use changes to package.json to force Docker not to use the cache
              # when we change our application's nodejs dependencies:
              COPY package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

              # From here we load our application's code in, therefore the previous docker
              # "layer" thats been cached will be used if possible
              WORKDIR /opt/app
              COPY . /opt/app

              EXPOSE 3000

              CMD ["node", "server.js"]


              This is where the package.json file added, install its dependencies and copy them into the container WORKDIR, where the app lives:



              ADD package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/


              To avoid the npm install phase on every docker build just copy those lines and change the ^/opt/app^ to the location your app lives inside the container.






              share|improve this answer





















              • 2





                That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

                – eljefedelrodeodeljefe
                Jun 3 '16 at 3:15






              • 2





                Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

                – Symmetric
                Jul 28 '16 at 17:24











              • For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

                – Marian Klühspies
                Feb 20 '17 at 11:20






              • 1





                The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

                – J. Fritz Barnes
                Apr 3 '17 at 16:46






              • 17





                I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

                – joniba
                May 31 '17 at 16:57














              92












              92








              92







              Ok so I found this great article about efficiency when writing a docker file.



              This is an example of a bad docker file adding the application code before running the RUN npm install instruction:



              FROM ubuntu

              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              WORKDIR /opt/app

              COPY . /opt/app
              RUN npm install
              EXPOSE 3001

              CMD ["node", "server.js"]


              By dividing the copy of the application into 2 COPY instructions (one for the package.json file and the other for the rest of the files) and running the npm install instruction before adding the actual code, any code change wont trigger the RUN npm install instruction, only changes of the package.json will trigger it. Better practice docker file:



              FROM ubuntu
              MAINTAINER David Weinstein <david@bitjudo.com>

              # install our dependencies and nodejs
              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              # use changes to package.json to force Docker not to use the cache
              # when we change our application's nodejs dependencies:
              COPY package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

              # From here we load our application's code in, therefore the previous docker
              # "layer" thats been cached will be used if possible
              WORKDIR /opt/app
              COPY . /opt/app

              EXPOSE 3000

              CMD ["node", "server.js"]


              This is where the package.json file added, install its dependencies and copy them into the container WORKDIR, where the app lives:



              ADD package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/


              To avoid the npm install phase on every docker build just copy those lines and change the ^/opt/app^ to the location your app lives inside the container.






              share|improve this answer















              Ok so I found this great article about efficiency when writing a docker file.



              This is an example of a bad docker file adding the application code before running the RUN npm install instruction:



              FROM ubuntu

              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              WORKDIR /opt/app

              COPY . /opt/app
              RUN npm install
              EXPOSE 3001

              CMD ["node", "server.js"]


              By dividing the copy of the application into 2 COPY instructions (one for the package.json file and the other for the rest of the files) and running the npm install instruction before adding the actual code, any code change wont trigger the RUN npm install instruction, only changes of the package.json will trigger it. Better practice docker file:



              FROM ubuntu
              MAINTAINER David Weinstein <david@bitjudo.com>

              # install our dependencies and nodejs
              RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
              RUN apt-get update
              RUN apt-get -y install python-software-properties git build-essential
              RUN add-apt-repository -y ppa:chris-lea/node.js
              RUN apt-get update
              RUN apt-get -y install nodejs

              # use changes to package.json to force Docker not to use the cache
              # when we change our application's nodejs dependencies:
              COPY package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

              # From here we load our application's code in, therefore the previous docker
              # "layer" thats been cached will be used if possible
              WORKDIR /opt/app
              COPY . /opt/app

              EXPOSE 3000

              CMD ["node", "server.js"]


              This is where the package.json file added, install its dependencies and copy them into the container WORKDIR, where the app lives:



              ADD package.json /tmp/package.json
              RUN cd /tmp && npm install
              RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/


              To avoid the npm install phase on every docker build just copy those lines and change the ^/opt/app^ to the location your app lives inside the container.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jul 24 '16 at 11:42

























              answered Mar 3 '16 at 14:21









              ohadgkohadgk

              1,2581610




              1,2581610








              • 2





                That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

                – eljefedelrodeodeljefe
                Jun 3 '16 at 3:15






              • 2





                Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

                – Symmetric
                Jul 28 '16 at 17:24











              • For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

                – Marian Klühspies
                Feb 20 '17 at 11:20






              • 1





                The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

                – J. Fritz Barnes
                Apr 3 '17 at 16:46






              • 17





                I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

                – joniba
                May 31 '17 at 16:57














              • 2





                That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

                – eljefedelrodeodeljefe
                Jun 3 '16 at 3:15






              • 2





                Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

                – Symmetric
                Jul 28 '16 at 17:24











              • For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

                – Marian Klühspies
                Feb 20 '17 at 11:20






              • 1





                The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

                – J. Fritz Barnes
                Apr 3 '17 at 16:46






              • 17





                I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

                – joniba
                May 31 '17 at 16:57








              2




              2





              That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

              – eljefedelrodeodeljefe
              Jun 3 '16 at 3:15





              That works. Some points though. ADD is discouraged in favor for COPY, afaik. COPY is even more effective. IMO, the last two paragraphs are not necessary, since they are duplicates and also from the app point-of-view it doesn't matter where on the files system the app lives, as long as WORKDIR is set.

              – eljefedelrodeodeljefe
              Jun 3 '16 at 3:15




              2




              2





              Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

              – Symmetric
              Jul 28 '16 at 17:24





              Better-still is to combine all of the apt-get commands onto one RUN, including an apt-get clean. Also, add ./node_modules to your .dockerignore, to avoid copying your working directory into your built container, and to speed up the build-context copy step of the build.

              – Symmetric
              Jul 28 '16 at 17:24













              For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

              – Marian Klühspies
              Feb 20 '17 at 11:20





              For what reason do you execute the copy command in a separate RUN? And does it matter if I move the node_modules package instead of copying it? Because it could get relatively big depending on how much you install

              – Marian Klühspies
              Feb 20 '17 at 11:20




              1




              1





              The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

              – J. Fritz Barnes
              Apr 3 '17 at 16:46





              The same approach but just adding package.json to the final resting position works fine as well (eliminating any cp/mv).

              – J. Fritz Barnes
              Apr 3 '17 at 16:46




              17




              17





              I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

              – joniba
              May 31 '17 at 16:57





              I don't get it. Why do you install in a temp directory and then move it to the app directory? Why not just install in the app directory? What am I missing here?

              – joniba
              May 31 '17 at 16:57













              19














              Weird! No one mentions multi-stage build.



              # ---- Base Node ----
              FROM alpine:3.5 AS base
              # install node
              RUN apk add --no-cache nodejs-current tini
              # set working directory
              WORKDIR /root/chat
              # Set tini as entrypoint
              ENTRYPOINT ["/sbin/tini", "--"]
              # copy project file
              COPY package.json .

              #
              # ---- Dependencies ----
              FROM base AS dependencies
              # install node packages
              RUN npm set progress=false && npm config set depth 0
              RUN npm install --only=production
              # copy production node_modules aside
              RUN cp -R node_modules prod_node_modules
              # install ALL node_modules, including 'devDependencies'
              RUN npm install

              #
              # ---- Test ----
              # run linters, setup and tests
              FROM dependencies AS test
              COPY . .
              RUN npm run lint && npm run setup && npm run test

              #
              # ---- Release ----
              FROM base AS release
              # copy production node_modules
              COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
              # copy app sources
              COPY . .
              # expose port and define CMD
              EXPOSE 5000
              CMD npm run start


              Awesome tuto here: https://codefresh.io/docker-tutorial/node_docker_multistage/






              share|improve this answer




























                19














                Weird! No one mentions multi-stage build.



                # ---- Base Node ----
                FROM alpine:3.5 AS base
                # install node
                RUN apk add --no-cache nodejs-current tini
                # set working directory
                WORKDIR /root/chat
                # Set tini as entrypoint
                ENTRYPOINT ["/sbin/tini", "--"]
                # copy project file
                COPY package.json .

                #
                # ---- Dependencies ----
                FROM base AS dependencies
                # install node packages
                RUN npm set progress=false && npm config set depth 0
                RUN npm install --only=production
                # copy production node_modules aside
                RUN cp -R node_modules prod_node_modules
                # install ALL node_modules, including 'devDependencies'
                RUN npm install

                #
                # ---- Test ----
                # run linters, setup and tests
                FROM dependencies AS test
                COPY . .
                RUN npm run lint && npm run setup && npm run test

                #
                # ---- Release ----
                FROM base AS release
                # copy production node_modules
                COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
                # copy app sources
                COPY . .
                # expose port and define CMD
                EXPOSE 5000
                CMD npm run start


                Awesome tuto here: https://codefresh.io/docker-tutorial/node_docker_multistage/






                share|improve this answer


























                  19












                  19








                  19







                  Weird! No one mentions multi-stage build.



                  # ---- Base Node ----
                  FROM alpine:3.5 AS base
                  # install node
                  RUN apk add --no-cache nodejs-current tini
                  # set working directory
                  WORKDIR /root/chat
                  # Set tini as entrypoint
                  ENTRYPOINT ["/sbin/tini", "--"]
                  # copy project file
                  COPY package.json .

                  #
                  # ---- Dependencies ----
                  FROM base AS dependencies
                  # install node packages
                  RUN npm set progress=false && npm config set depth 0
                  RUN npm install --only=production
                  # copy production node_modules aside
                  RUN cp -R node_modules prod_node_modules
                  # install ALL node_modules, including 'devDependencies'
                  RUN npm install

                  #
                  # ---- Test ----
                  # run linters, setup and tests
                  FROM dependencies AS test
                  COPY . .
                  RUN npm run lint && npm run setup && npm run test

                  #
                  # ---- Release ----
                  FROM base AS release
                  # copy production node_modules
                  COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
                  # copy app sources
                  COPY . .
                  # expose port and define CMD
                  EXPOSE 5000
                  CMD npm run start


                  Awesome tuto here: https://codefresh.io/docker-tutorial/node_docker_multistage/






                  share|improve this answer













                  Weird! No one mentions multi-stage build.



                  # ---- Base Node ----
                  FROM alpine:3.5 AS base
                  # install node
                  RUN apk add --no-cache nodejs-current tini
                  # set working directory
                  WORKDIR /root/chat
                  # Set tini as entrypoint
                  ENTRYPOINT ["/sbin/tini", "--"]
                  # copy project file
                  COPY package.json .

                  #
                  # ---- Dependencies ----
                  FROM base AS dependencies
                  # install node packages
                  RUN npm set progress=false && npm config set depth 0
                  RUN npm install --only=production
                  # copy production node_modules aside
                  RUN cp -R node_modules prod_node_modules
                  # install ALL node_modules, including 'devDependencies'
                  RUN npm install

                  #
                  # ---- Test ----
                  # run linters, setup and tests
                  FROM dependencies AS test
                  COPY . .
                  RUN npm run lint && npm run setup && npm run test

                  #
                  # ---- Release ----
                  FROM base AS release
                  # copy production node_modules
                  COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
                  # copy app sources
                  COPY . .
                  # expose port and define CMD
                  EXPOSE 5000
                  CMD npm run start


                  Awesome tuto here: https://codefresh.io/docker-tutorial/node_docker_multistage/







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Apr 30 '18 at 8:54









                  Abdennour TOUMIAbdennour TOUMI

                  36.4k15145163




                  36.4k15145163























                      15














                      I've found that the simplest approach is to leverage Docker's copy semantics:




                      The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .




                      This means that if you first explicitly copy the package.json file and then run the npm install step that it can be cached and then you can copy the rest of the source directory. If the package.json file has changed, then that will be new and it will re-run the npm install caching that for future builds.



                      A snippet from the end of a Dockerfile would look like:



                      # install node modules
                      WORKDIR /usr/app
                      COPY package.json /usr/app/package.json
                      RUN npm install

                      # install application
                      COPY . /usr/app





                      share|improve this answer





















                      • 3





                        Instead of cd /usr/app you can/should use WORKDIR /usr/app.

                        – Vladimir Vukanac
                        Jan 17 at 15:53











                      • @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

                        – J. Fritz Barnes
                        Jan 25 at 15:17











                      • is npm install run in /usr/app directory or . ?

                        – user557657
                        Feb 1 at 19:06






                      • 1





                        @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

                        – J. Fritz Barnes
                        Feb 7 at 14:35











                      • @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

                        – user557657
                        Feb 8 at 15:20
















                      15














                      I've found that the simplest approach is to leverage Docker's copy semantics:




                      The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .




                      This means that if you first explicitly copy the package.json file and then run the npm install step that it can be cached and then you can copy the rest of the source directory. If the package.json file has changed, then that will be new and it will re-run the npm install caching that for future builds.



                      A snippet from the end of a Dockerfile would look like:



                      # install node modules
                      WORKDIR /usr/app
                      COPY package.json /usr/app/package.json
                      RUN npm install

                      # install application
                      COPY . /usr/app





                      share|improve this answer





















                      • 3





                        Instead of cd /usr/app you can/should use WORKDIR /usr/app.

                        – Vladimir Vukanac
                        Jan 17 at 15:53











                      • @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

                        – J. Fritz Barnes
                        Jan 25 at 15:17











                      • is npm install run in /usr/app directory or . ?

                        – user557657
                        Feb 1 at 19:06






                      • 1





                        @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

                        – J. Fritz Barnes
                        Feb 7 at 14:35











                      • @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

                        – user557657
                        Feb 8 at 15:20














                      15












                      15








                      15







                      I've found that the simplest approach is to leverage Docker's copy semantics:




                      The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .




                      This means that if you first explicitly copy the package.json file and then run the npm install step that it can be cached and then you can copy the rest of the source directory. If the package.json file has changed, then that will be new and it will re-run the npm install caching that for future builds.



                      A snippet from the end of a Dockerfile would look like:



                      # install node modules
                      WORKDIR /usr/app
                      COPY package.json /usr/app/package.json
                      RUN npm install

                      # install application
                      COPY . /usr/app





                      share|improve this answer















                      I've found that the simplest approach is to leverage Docker's copy semantics:




                      The COPY instruction copies new files or directories from and adds them to the filesystem of the container at the path .




                      This means that if you first explicitly copy the package.json file and then run the npm install step that it can be cached and then you can copy the rest of the source directory. If the package.json file has changed, then that will be new and it will re-run the npm install caching that for future builds.



                      A snippet from the end of a Dockerfile would look like:



                      # install node modules
                      WORKDIR /usr/app
                      COPY package.json /usr/app/package.json
                      RUN npm install

                      # install application
                      COPY . /usr/app






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Jan 25 at 15:16

























                      answered Apr 3 '17 at 17:01









                      J. Fritz BarnesJ. Fritz Barnes

                      44846




                      44846








                      • 3





                        Instead of cd /usr/app you can/should use WORKDIR /usr/app.

                        – Vladimir Vukanac
                        Jan 17 at 15:53











                      • @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

                        – J. Fritz Barnes
                        Jan 25 at 15:17











                      • is npm install run in /usr/app directory or . ?

                        – user557657
                        Feb 1 at 19:06






                      • 1





                        @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

                        – J. Fritz Barnes
                        Feb 7 at 14:35











                      • @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

                        – user557657
                        Feb 8 at 15:20














                      • 3





                        Instead of cd /usr/app you can/should use WORKDIR /usr/app.

                        – Vladimir Vukanac
                        Jan 17 at 15:53











                      • @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

                        – J. Fritz Barnes
                        Jan 25 at 15:17











                      • is npm install run in /usr/app directory or . ?

                        – user557657
                        Feb 1 at 19:06






                      • 1





                        @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

                        – J. Fritz Barnes
                        Feb 7 at 14:35











                      • @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

                        – user557657
                        Feb 8 at 15:20








                      3




                      3





                      Instead of cd /usr/app you can/should use WORKDIR /usr/app.

                      – Vladimir Vukanac
                      Jan 17 at 15:53





                      Instead of cd /usr/app you can/should use WORKDIR /usr/app.

                      – Vladimir Vukanac
                      Jan 17 at 15:53













                      @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

                      – J. Fritz Barnes
                      Jan 25 at 15:17





                      @VladimirVukanac :+1: on using WORKDIR; I've updated the answer above to take that into account.

                      – J. Fritz Barnes
                      Jan 25 at 15:17













                      is npm install run in /usr/app directory or . ?

                      – user557657
                      Feb 1 at 19:06





                      is npm install run in /usr/app directory or . ?

                      – user557657
                      Feb 1 at 19:06




                      1




                      1





                      @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

                      – J. Fritz Barnes
                      Feb 7 at 14:35





                      @user557657 The WORKDIR sets the directory within the future image from which the command will be run. So in this case, it's running npm install from /usr/app within the image which will create a /usr/app/node_modules with dependencies installed from the npm install.

                      – J. Fritz Barnes
                      Feb 7 at 14:35













                      @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

                      – user557657
                      Feb 8 at 15:20





                      @J.FritzBarnes thanks a lot. isnt COPY . /usr/app would copy package.json file again in /usr/app with the rest of the files?

                      – user557657
                      Feb 8 at 15:20











                      5














                      I imagine you may already know, but you could include a .dockerignore file in the same folder containing



                      node_modules
                      npm-debug.log


                      to avoid bloating your image when you push to docker hub






                      share|improve this answer




























                        5














                        I imagine you may already know, but you could include a .dockerignore file in the same folder containing



                        node_modules
                        npm-debug.log


                        to avoid bloating your image when you push to docker hub






                        share|improve this answer


























                          5












                          5








                          5







                          I imagine you may already know, but you could include a .dockerignore file in the same folder containing



                          node_modules
                          npm-debug.log


                          to avoid bloating your image when you push to docker hub






                          share|improve this answer













                          I imagine you may already know, but you could include a .dockerignore file in the same folder containing



                          node_modules
                          npm-debug.log


                          to avoid bloating your image when you push to docker hub







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jan 25 '17 at 15:42









                          usrrnameusrrname

                          15919




                          15919























                              0














                              you don't need to use tmp folder, just copy package.json to your container's application folder, do some install work and copy all files later.



                              COPY app/package.json /opt/app/package.json
                              RUN cd /opt/app && npm install
                              COPY app /opt/app





                              share|improve this answer
























                              • so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                                – user557657
                                Feb 1 at 19:19
















                              0














                              you don't need to use tmp folder, just copy package.json to your container's application folder, do some install work and copy all files later.



                              COPY app/package.json /opt/app/package.json
                              RUN cd /opt/app && npm install
                              COPY app /opt/app





                              share|improve this answer
























                              • so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                                – user557657
                                Feb 1 at 19:19














                              0












                              0








                              0







                              you don't need to use tmp folder, just copy package.json to your container's application folder, do some install work and copy all files later.



                              COPY app/package.json /opt/app/package.json
                              RUN cd /opt/app && npm install
                              COPY app /opt/app





                              share|improve this answer













                              you don't need to use tmp folder, just copy package.json to your container's application folder, do some install work and copy all files later.



                              COPY app/package.json /opt/app/package.json
                              RUN cd /opt/app && npm install
                              COPY app /opt/app






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Nov 17 '18 at 4:42









                              Mike ZhangMike Zhang

                              101110




                              101110













                              • so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                                – user557657
                                Feb 1 at 19:19



















                              • so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                                – user557657
                                Feb 1 at 19:19

















                              so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                              – user557657
                              Feb 1 at 19:19





                              so you are executing npm install in container directory /opt/app then copying all files from local machine to /opt/app ?

                              – user557657
                              Feb 1 at 19:19


















                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f35774714%2fhow-to-cache-the-run-npm-install-instruction-when-docker-build-a-dockerfile%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Xamarin.iOS Cant Deploy on Iphone

                              Glorious Revolution

                              Dulmage-Mendelsohn matrix decomposition in Python