How to Optimize Docker Images for Laravel Apps: A Simple Guide

If you already used Docker with a Laravel app, you know the final image can get big and that affects build time, deployment speed, and even storage cost.

In this post, I’ll show you how to make you Docker image smaller and faster using multi-stage builds, lightweight images, and a few best practices.

Basic Structure

Here is a real example using PHP 8.3 + Laravel + Composer + Node for front assets:

# Stage 1: Build the app dependencies
FROM composer:2.7 as vendor

WORKDIR /app

COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --optimize-autoloader

COPY . .

# Stage 2: Build frontend assets (optional)
FROM node:20-alpine as frontend

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

# Stage 3: Final production image (clean and light)
FROM php:8.3-fpm-alpine

RUN apk add --no-cache 
    bash curl libpng libjpeg-turbo-dev libzip-dev oniguruma-dev 
    && docker-php-ext-install pdo pdo_mysql zip mbstring

WORKDIR /var/www

COPY --from=vendor /app /var/www
COPY --from=frontend /app/public/build /var/www/public/build

RUN chown -R www-data:www-data /var/www

USER www-data

Best Practices

  • Use Alpine Images they are much smaller and good for prod.
  • Split the build into stages This keeps dev tools out of the final image.
  • Do not install Composer or Node in the final Image this reduces the size and security risks.
  • Don’t use COPY . . at the end copy only what you really need (no .env, .git, tests, etc).

Before And After

A non optimize image can be 1.2GB or more.
With multi-stage builds and Alpine, it can be under 200MB!

Extra Security Tips

  • Use USER www-data at the end
  • Add a .dockerignore file
node_modules
vendor
.env
.git
tests

Final Thoughts

Optimized Docker images are faster, safer, and cheaper.
Have youy optimized you Laravel Setup ? Do you have other tips ?

Similar Posts