Optimizing Docker Layer Caching for Private PHP/Laravel Packages with Multi-Stage Builds and BuildKit Secrets
21:42 05 May 2026

i am trying to optimize a Docker Multi-Stage build for a Laravel application that requires private GitHub packages. I have two main issues that I can't seem to solve efficiently:

Caching vs. Secrets: I’m using docker build-kit secrets (--mount=type=secret) to pass my GitHub Token for composer install. However, every time I change the secret or even some unrelated files, the composer install layer re-runs, which is very slow. How can I ensure that composer install stays cached as long as composer.lock hasn't changed, even when using secrets?

Secure Layering: I want to make sure the private repo credentials never end up in the final image or any intermediate layer history.

Here is my current Dockerfile structure:

Dockerfile
# syntax=docker/dockerfile:1
FROM php:8.2-fpm-alpine AS builder

WORKDIR /app

# Install system dependencies
RUN apk add --no-cache git unzip

# Copy dependency files
COPY composer.json composer.lock ./

# The problem layer:
RUN --mount=type=secret,id=composer_auth,target=/root/.composer/auth.json \
    composer install --no-dev --optimize-autoloader --no-scripts

COPY . .

# Final Stage
FROM php:8.2-fpm-alpine
COPY --from=builder /app /var/www

My questions:

Is there a specific way to mount the secret so it doesn't invalidate the cache unnecessarily?

Should I be using a separate RUN for a cache mount (type=cache,target=/root/.composer/cache) alongside the secret mount?

php laravel docker security docker-compose