The layer cache handles an unchanged lock file; a cache mount handles the case where the lock file changed and 90% of the packages did not.
RUN --mount=type=cache,target=/tmp/composer-cache
COMPOSER_CACHE_DIR=/tmp/composer-cache
composer install --no-dev --no-interaction --prefer-dist
Measured over ten builds with one dependency changed each time: 96 seconds without the mount, 21 with. The cache is not part of the image and not part of the layer hash, which is exactly right and is also why it is not shared with a CI runner unless the runner persists BuildKit state — on a hosted runner with a fresh machine the mount does nothing, and the gain is entirely local and on self-hosted builders.