Reader Stacks

What Is Composer? Installing and Using PHP's Package Manager

Composer manages a project's external library dependencies and their versions — every modern PHP framework, Laravel included, is built on top of it, not alongside it.

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.

Topics: Developer Productivity