Composer install in Dockerfile Without Breaking Cache

When building a Docker image for your PHP application there are some steps you should take to prevent the cache from being invalidated prematurely. Cache misses can slow down the build process drastically.

The first instruction is to install Composer. Then we change the working directory to /app which is created if it doesn’t already exist.

The COPY instruction will copy your application’s source directory to the file system of the container. These files have likely been changed and the COPY instruction will invalidate the cache, which means that all subsequent Dockerfile instructions will run on every build.

Having Composer install all its dependencies on every build is not ideal.

Instead of copying all the source files we only copy composer.json and composer.lock. These rarely change and will not invalidate the cache. Neither will the RUN instruction unless you change the command itself.

With these files in place we can run composer install before the cache is invalidated by the new application source files; our dependencies will not be downloaded with every Docker build. However, without the source files we cannot run our Composer scripts or build the autoloader just yet, so we use the --no-scripts and --no-autoloader flags.

Then, only after we have copied all the source files, we dump the autoloader and run the scripts.

Now Docker is reusing the cache for all but the last layer where the source code is copied.

Create a .dockerignore file

Because we’re copying the entire source directory into the image, any file change will invalidate the cache, even the change of a log file. We can easily remove certain files and directories from the build context by adding a .dockerignore file which lists all the items we want to exclude, e.g. a log/ directory.

Generally speaking, any file that isn’t required by your image should be added to .dockerignore in order to increase build performance.