laravel/sail
Laravel Sail is a Docker-powered local development environment for Laravel that works on macOS, Windows (WSL2), and Linux. With a simple CLI, it lets you start building without any prior Docker experience.
Architecture fit. Laravel Sail is not a runtime library — it is a developer-environment distribution: a Composer package (laravel/sail, dev-only) that ships (a) per-PHP-version Dockerfiles (currently 8.0 through 8.5), (b) a compose.yaml template with service stubs for MySQL 8.4, PostgreSQL 18, MariaDB, Redis, Valkey, Memcached, Meilisearch, Typesense, MinIO/RustFS, RabbitMQ, MongoDB, Selenium and Mailpit, and (c) a thin sail shell wrapper invoked as vendor/bin/sail. There is essentially no application-facing API surface, so architectural coupling is near zero: adoption is a repository-level decision (Composer dev dependency + generated compose.yaml + .env variables), not an application-code decision. This makes it a low-blast-radius addition, but also means the package provides no abstractions you can code against — the value is entirely in convention and maintenance of the image/stub set.
Integration feasibility. High for any team already on Laravel 9–13. The standard path is composer require laravel/sail --dev then php artisan sail:install --with=<services>, which writes compose.yaml, patches .env/phpunit.xml DB settings, and gives you sail up|down|artisan|composer|node|test. Prerequisites are Docker Desktop (macOS/Windows WSL2) or Docker Engine/Colima/Podman on Linux; SAIL_DOCKER_BINARY (added v1.55) covers Podman, and WWWUSER/WWWGROUP plus the APP_SERVICE env control UID mapping and service targeting. The main integration cost is social, not technical: convincing developers to route commands through sail rather than a host PHP/Node toolchain.
Technical risk.
compose.yaml as a deployment artifact.8.0→8.4, Postgres 17→18, Node 22→24, Ubuntu 24.04). Stub regeneration can silently change a developer's local database engine version relative to staging.docker-compose.yml→compose.yaml rename in v1.46 that can orphan existing workflows.Key questions.
laravel/sail exactly in composer.json and commit the generated compose.yaml, or regenerate from stubs on upgrade?Stack fit. Sail fits cleanly where the org is Laravel-centric and Docker is already sanctioned. It supports Laravel 12 (v1.41) and Laravel 13 (v1.53) and tracks PHP 8.5 and Swoole, which means it will not become the reason a framework upgrade stalls. For polyglot repos, monorepos with non-Laravel services, or teams already standardized on a shared devcontainer, Sail is a redundant second convention and should be skipped.
Migration path.
docker-compose.yml/compose.yaml files and record service versions — this becomes the drift baseline.sail:install --with= matching the inventory, and diff generated stubs against the current stack. Treat the diff as the migration backlog.compose.yaml rather than layering a second file; keep bespoke overrides in a clearly commented section so stub regeneration is a reviewable diff..env.example, compose.yaml, sail invocation documented in the README, Makefile targets) so new repos start aligned.compose.yaml, restore prior stack" — trivially reversible, which is the strongest argument for piloting broadly.Compatibility. PHP 8.0–8.5 images; Node 24 base; Laravel 12/13 tested in-repo. Podman via SAIL_DOCKER_BINARY; PHP extension customization via the PHP_EXTENSIONS build arg (v1.63) reduces Dockerfile forks. Watch items: the compose.yaml rename, MySQL 8.4 and Postgres 18 defaults, and phpunit.xml DB rewriting behavior (whitespace-tolerance fix in v1.64).
Sequencing. Pin Sail and lock it first → generate and commit compose.yaml → validate CI (sail test or an equivalent runner using the same image) → then, and only then, retire legacy local setup docs. Do not enable Sail as a CI runtime before the local pilot has stabilized, or you will debug two environments simultaneously.
Maintenance. Upstream is actively maintained within the Laravel organization: frequent releases (v1.67 is current in the supplied changelog), Dependabot with pinned Actions SHAs and a 5-day cooldown, changelog-per-release, MIT license. Ongoing cost is low but nonzero: you must review Sail bumps, because releases routinely include base-image and service-major changes that alter local behavior. Budget roughly one review cycle per Sail minor release, plus regeneration and diffing of compose.yaml.
Support. Community support only — GitHub issues, Laravel docs, no vendor SLA. Acceptable for local tooling; not acceptable as the sole dependency for anything gating release. Escalation path for a blocked developer is "fall back to raw docker compose," which should be documented explicitly rather than improvised.
Scaling. Sail scales to developer count, not to traffic — it has no production role and should never be deployed. The real scaling concern is fleet consistency: N developers × M repos × drifting stub versions produces "works on my machine" reports that are expensive to triage. Mitigate with a pinned version, a committed compose.yaml, and a shared template. For CI, the same image reused across jobs is efficient; per-job rebuilds of the Dockerfile are not (cache your layers or pull a published image).
Failure modes and mitigations.
APP_PORT/FORWARD_*_PORT overrides in the template.WWWUSER/WWWGROUP; provide a sail artisan-based diagnostic snippet.depends_on: condition: service_healthy usage conservative and know how to inspect container health.schedule:work.Ramp-up. Very low for developers with any Docker exposure — the README's core promise ("other than Docker, no software required," simple CLI, no prior Docker experience needed) holds, and sail mirrors artisan/composer/npm syntax closely enough that muscle memory transfers. Plan half a day for onboarding including a first sail up and a test run. The steeper cost is for platform/DevOps owners who must own version pinning, CI parity, and stub drift — that is a real, ongoing responsibility that Sail's simplicity obscures. Net recommendation: adopt for Laravel-centric teams as a dev-only, pinned dependency with a committed compose.yaml; do not adopt where a shared devcontainer strategy already exists, and do not let it substitute for a deliberate production environment definition.
How can I help you explore Laravel packages today?