Composer Scripts — One-Command Developer Onboarding
Series: Every Laravel Project Should Have These Building Blocks
Part: 30 of 35 Level: Beginner–Intermediate Prerequisites: None
What You’ll Learn
- Why
composer.jsonscripts are better than a README with steps - The
composer setuponboarding script composer lint:fix,composer lint,composer test:typescomposer dev— running everything in parallel- Auto-installing git hooks via
post-autoload-dump
The Problem with README Instructions
Every project has a README that says something like:
Getting started:
1. cp .env.example .env
2. composer install
3. php artisan key:generate
4. php artisan migrate
5. php artisan db:seed
6. npm install && npm run build
Six steps, and that’s for a simple project. When a new developer joins, they inevitably miss a step, get an error, and spend 30 minutes debugging an environment that should have taken 5 minutes. When you change the setup process, the README gets outdated.
composer scripts make setup a single command.
The composer.json Scripts Block
{
"scripts": {
"setup": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
"@php artisan key:generate --ansi",
"@php artisan migrate --ansi",
"@php artisan db:seed --ansi",
"npm install",
"npm run build"
],
"dev": [
"Composer\\Config::disableProcessTimeout",
"@putenv SHELL_VERBOSITY=1",
"@php artisan serve &",
"@php artisan queue:listen --tries=1 &",
"@php artisan pail --timeout=0 &",
"npm run dev"
],
"lint": [
"vendor/bin/rector --dry-run",
"vendor/bin/pint --test"
],
"lint:fix": [
"vendor/bin/rector",
"vendor/bin/pint"
],
"test": "php artisan test --compact",
"test:types": "vendor/bin/phpstan analyse --memory-limit=512M",
"quality": [
"@lint:fix",
"@test:types",
"@test"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi",
"@php -r \"file_exists('.hooks/pre-commit') && shell_exec('git config core.hooksPath .hooks');\"",
"@php -r \"file_exists('.hooks/pre-commit') && shell_exec('chmod +x .hooks/pre-commit');\""
]
}
}
What Each Script Does
composer setup
First-time project setup, idempotent:
"setup": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
"@php artisan key:generate --ansi",
"@php artisan migrate --ansi",
"@php artisan db:seed --ansi",
"npm install",
"npm run build"
]
The file_exists('.env') || copy(...) line only copies .env.example if .env doesn’t already exist — so running composer setup again after setup won’t overwrite customized env values.
A new developer runs composer install && composer setup and they’re done.
composer dev
Start everything needed for local development simultaneously:
"dev": [
"Composer\\Config::disableProcessTimeout",
"@php artisan serve &",
"@php artisan queue:listen --tries=1 &",
"@php artisan pail --timeout=0 &",
"npm run dev"
]
disableProcessTimeout prevents Composer from killing long-running commands. The & runs each command in the background. npm run dev runs in the foreground, so the whole thing stays alive until you Ctrl+C.
One command replaces:
- Terminal 1:
php artisan serve - Terminal 2:
php artisan queue:listen - Terminal 3:
php artisan pail - Terminal 4:
npm run dev
composer lint / composer lint:fix
Check vs. fix:
"lint": ["vendor/bin/rector --dry-run", "vendor/bin/pint --test"],
"lint:fix": ["vendor/bin/rector", "vendor/bin/pint"]
lint is for CI — it fails if anything needs changing, without making changes. lint:fix is for local development — it makes the changes.
composer test:types
Static analysis only:
"test:types": "vendor/bin/phpstan analyse --memory-limit=512M"
composer quality
Before pushing a PR:
"quality": [
"@lint:fix",
"@test:types",
"@test"
]
Runs: Rector → Pint → Larastan → Tests. If all pass, you’re ready to push.
post-autoload-dump — Auto-Installing Git Hooks
Every composer install or composer update triggers post-autoload-dump. Use it to auto-install the git pre-commit hook:
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi",
"@php -r \"file_exists('.hooks/pre-commit') && shell_exec('git config core.hooksPath .hooks');\"",
"@php -r \"file_exists('.hooks/pre-commit') && shell_exec('chmod +x .hooks/pre-commit');\""
]
This means:
- Developer runs
composer install - Git hooks path is automatically configured to
.hooks/ - Pre-commit hook is made executable
- Every subsequent
git commitautomatically runs the quality checks
Developers never manually install the hooks. They can’t forget.
The README That Ships With This Setup
With these scripts in place, your README’s “Getting Started” section becomes:
## Getting Started
```bash
composer install
composer setup
That’s it. For local development:
composer dev
Before pushing:
composer quality
Four lines of README instead of six manual steps.
Key Takeaways
composer setupwraps all first-time setup into one command. Usefile_exists()checks to make it idempotent.composer devstarts the HTTP server, queue worker, log viewer, and Vite together. One command replaces four terminals.composer lintchecks only;composer lint:fixfixes. Match CI vs. local workflows.composer quality= lint:fix + static analysis + tests. The pre-push command.post-autoload-dumpauto-installs git hooks on everycomposer install— developers can’t forget to set them up.
Tips and Gotchas
⚠️ Warning: The
composer devscript uses&to background processes. On Windows,&doesn’t work in bash — this script requires WSL or a POSIX-compatible shell. Windows developers should usecomposer run devinside WSL or add a PowerShell alternative.
💡 Tip: Add
composer setupto your onboarding documentation as the only step aftercomposer install. Ifcomposer setupfails, that’s a bug in your setup script — not a developer problem. Fix the script.
🔥 Expert Note: The
post-autoload-dumphook runs on everycomposer install,composer update, andcomposer require. This means your git hooks are reinstalled every time someone adds a package. New team members who runcomposer installafter cloning the repo automatically get the hooks — no manual step, no opportunity to skip it.
Further Reading
- Composer Docs: Scripts
- Composer Docs:
post-autoload-dump - Laravel Pail — the real-time log viewer used in
composer dev