In this article

“Heap, Heap, Array!”

Setting up a new Laravel project with Sail – without installing PHP

It’s surprisingly hard to figure out how you can create and run a new Laravel app via Docker without installing PHP first.

Who else wants to start new Laravel projects Anyplace, Anywhere, Anytime?
Nena feat. Kim Wilde – Anyplace, Anywhere, Anytime

Who else wants to start new Laravel projects Anyplace, Anywhere, Anytime?

Recently I tried to set up a new Laravel project using only Docker Compose and found it surprisingly hard to find simple instructions on how to do this.

Laravel’s installation guide assumes that PHP and Node.js are available on your machine, but I don’t have PHP installed on my Mac, nor do I want to.

Laravel’s first-party Sail package aims to provide a beginner-friendly interface to Docker. It does this well in my experience, but only once it’s set up – and therein lies the problem, because Sail also assumes that a native PHP interpreter is present on your system.

Docker’s guide on developing Laravel applications with Docker Compose, of course, doesn’t make this assumption. It attempts to do things “the right way”, however, which adds a lot of needless complexity and makes the setup harder to understand.

If you are new to Laravel – or even PHP development in general – it’s probably wise to start with Laravel Sail.

To make the whole process of installing and configuring Sail easier, I wrote a one-liner script that helps you set up a new Sail-powered Laravel project. By default, it creates new projects named example, using PHP 8.4 and Node.js 22, but you can easily customise this by modifying the values on the first three lines.

Terminal
APP_NAME=example
PHP_VERSION=8.4
NODE_VERSION=22
docker run \
--rm \
--interactive \
--tty \
--volume $(pwd):/app \
--workdir /app \
"php:$PHP_VERSION-trixie" \
bash -c " \
set -e; \
apt-get update; \
curl -sLS https://getcomposer.org/installer \
| php -- --install-dir=/usr/bin/ --filename=composer; \
curl -fsSL \"https://deb.nodesource.com/setup_$NODE_VERSION.x\" \
| bash -; \
apt-get install --assume-yes git nodejs zip; \
composer global require laravel/installer; \
/root/.composer/vendor/bin/laravel new $APP_NAME; \
cd $APP_NAME; \
php artisan sail:install \
" \
&& cd $APP_NAME \
&& ./vendor/bin/sail up -d \
&& ./vendor/bin/sail php artisan migrate

“Why didn’t you…”

There a few reasons why I ended up with this solution in particular; some of them good, some less good.

Use Sail’s Dockerfile

Ideally, the image we use to install the framework should contain the same PHP and Node.js versions as the image we use to run the framework.

It would therefore make sense to install Laravel using Sail’s Docker image. The image doesn’t seem to be published anywhere, but we can find its Dockerfile in Sail’s GitHub repository. Theoretically, we can directly build a Docker image from that Dockerfile and use it to run the installer:

Terminal
docker build \
--tag sail \
https://github.com/laravel/sail.git#1.x:runtimes/8.4
docker run

However, this method has two major drawbacks. The first is that the image takes a long time to build. The second, and probably larger, drawback is that it doesn’t work.

Use the Composer image

I thought I could get away with simply using the official Composer image as it already comes with PHP and Composer pre-installed:

Terminal
APP_NAME=example
docker run \
--rm \
--interactive \
--tty \
--volume $(pwd):/app \
composer \
bash -c " \
composer global require laravel/installer \
&& \
/tmp/vendor/bin/laravel new $APP_NAME \
&& \
cd $APP_NAME \
&& \
php artisan sail:install
" \
&& cd $APP_NAME \
&& ./vendor/bin/sail up -d \
&& ./vendor/bin/sail php artisan migrate \
&& ./vendor/bin/sail npm install \
&& ./vendor/bin/sail npm run build

This actually works fine, even though the installer may show the message sh: npm: not found if you answer “Yes” in the following prompt because Node.js isn’t present in the Composer image:

┌ Would you like to run npm install and npm run build? ────────┐
│ ● Yes / ○ No │
└──────────────────────────────────────────────────────────────┘

This method is much faster and has fewer “moving parts” than the final solution. The only reason I prefer the final solution over this is that the warning message may be confusing to (especially student and junior) developers.

Use images that also include npm

If the main drawback of the Composer image is that it doesn’t include Node.js, could we use other images that include both PHP and Node.js?

Technically we could. However, many of the images I found that include both runtimes are unofficial, unmaintained, and sometimes a little suspicious…

This article appears in