Composer is PHP's dependency manager — it tracks which external libraries a project needs, resolves compatible versions between them, downloads them, and generates the autoloading code that makes them usable with a simple use statement. Every modern PHP framework, including Laravel, is installed and managed through Composer rather than as a standalone download.
1. Installing Composer
# Linux/macOS
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version
Composer is itself distributed as a PHP file (composer.phar) — moving it into a directory on the system PATH (like /usr/local/bin) makes the composer command available globally, rather than needing to be invoked as php composer.phar from a specific folder every time.
2. composer.json — the project's dependency manifest
{
"require": {
"php": "^8.2",
"laravel/framework": "^11.0",
"guzzlehttp/guzzle": "^7.8"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
}
}
require lists production dependencies; require-dev lists packages only needed during development (testing tools, debugging aids) — the distinction matters because a production deployment typically installs with --no-dev, skipping anything listed only under require-dev.
3. Installing packages
composer require guzzlehttp/guzzle
composer require phpunit/phpunit --dev
Running composer require both adds the package to composer.json and immediately downloads it — no separate manual editing of the JSON file is needed for the common case of adding a new dependency.
4. composer.lock — exact, reproducible versions
composer.json specifies version constraints (^11.0 means "11.0 or any later 11.x release, but not 12.0"); composer.lock records the exact specific version actually resolved and installed at that moment. Committing composer.lock to version control (which is standard practice) ensures every environment — a teammate's machine, CI, production — installs the identical exact versions, not just "compatible" ones that could otherwise drift between environments over time.
5. composer install vs. composer update
composer install # installs the EXACT versions recorded in composer.lock
composer update # re-resolves and installs the latest versions matching composer.json's constraints
This distinction matters more than it might seem — composer install is what should run on every deploy and every fresh clone (reproducible, using the locked versions); composer update is a deliberate action for intentionally bumping dependency versions, and should be a conscious choice, not something that happens accidentally as part of routine deployment.
6. Autoloading
require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();
Composer generates vendor/autoload.php, which registers an autoloader mapping namespaces to file paths automatically (following the PSR-4 standard) — this is what makes use SomeVendor\SomeClass; work without a manual require statement for every single class file a project uses.
7. Autoloading a project's own classes too
{
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
composer dump-autoload
Composer isn't limited to third-party packages — a project's own namespace-to-directory mapping (exactly what powers Laravel's App\ namespace pointing at the app/ directory) is configured the same way, and needs composer dump-autoload re-run whenever that mapping itself changes, though not for every individual new class added within an already-mapped directory.