Docker layer caching rewards the order of your Dockerfile

Each instruction produces a layer, and a layer is reused only if every instruction before it is unchanged. Copying the whole application before installing dependencies invalidates the dependency layer on every source edit, so each build reinstalls everything.

# slow: any source change re-runs composer install
COPY . /app
RUN composer install

# fast: dependencies re-install only when the manifests change
COPY composer.json composer.lock /app/
RUN composer install --no-scripts --no-autoloader
COPY . /app
RUN composer dump-autoload --optimize

The rule is to order instructions from least to most frequently changed, which for almost every application means manifests, then dependencies, then source. Splitting the install into a dependency step and an autoload step is what makes it work with Composer, since the autoloader needs the source that has not been copied yet.