Skip to main content

Multi-Stage Builds

php-ci is a pre-built CI runtime — pull a tag and run tests. You usually do not need a custom Dockerfile. Reach for multi-stage builds when you must bake in proprietary tooling, OS packages not in the base image, or a golden application artifact.

When php-ci alone is enough

  • PHPUnit, Pest, PHPStan, PHPCS and Composer scripts
  • TYPO3 and Laravel test suites with standard extensions
  • Matrix jobs across PHP 8.1–8.4

See Installation for pull and pin commands.

Extending php-ci in a Dockerfile

Add project-specific OS packages on top of a pinned php-ci tag:

FROM himanshuramavat/php-ci:8.3

USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
your-package \
&& rm -rf /var/lib/apt/lists/*
USER www-data

Build once, push to your registry, and reference that image in CI.

Multi-stage pattern

Use a builder stage for Composer and a slim runtime only when you ship containers to production — not for typical test jobs:

# Builder — install vendor/
FROM himanshuramavat/php-ci:8.3 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --no-interaction

# Runtime — copy vendor + app (example only)
FROM himanshuramavat/php-ci:8.3
WORKDIR /app
COPY --from=vendor /app/vendor ./vendor
COPY . .

For CI test pipelines, mounting the repo with -v "$(pwd):/app" is simpler and faster than rebuilding layers on every commit.

Layer caching in CI

Cache Composer's vendor/ directory between jobs instead of baking dependencies into an image. Examples: