How to use local packages in Composer: a guide for PHP developers
Source: Dev.to
When working on a PHP project, it’s common to rely on external libraries published on Packagist. Composer makes installing and managing these dependencies effortless. But what if you need to work with a dependency locally, outside Packagist?
Why use a local path repository?
- Rapid iteration – Test changes in a library immediately without publishing a new version or pushing to GitHub.
- Deep debugging – Add logging, inspect internal state, or step through the library code.
- Pull‑request testing – Validate changes in a real project before submitting a PR.
- Offline development – Useful in environments that block access to GitHub or Packagist.
- Experimental work – Try breaking changes or internal APIs without publishing anything.
- Version‑management convenience – Skip bumping semantic versions while iterating quickly.
Typical scenario
Your project’s composer.json might look like this:
{
"require": {
"storyblok/php-management-api-client": "@dev",
"vlucas/phpdotenv": "^5.6"
},
"repositories": [
{
"type": "path",
"url": "../php-management-api-client"
}
]
}
The repositories entry with "type": "path" tells Composer to use the copy located at ../php-management-api-client instead of downloading the package from Packagist. This allows you to clone the library next to your project, modify it, and see the changes instantly.
Setting up the local package
-
Place the library near your project
~/Projects/my-project ~/Projects/php-management-api-client ← cloned libraryThe folder name does not need to match the package name; only the path must match the URL defined in
composer.json. -
Add a path repository with symlink option
// composer.json (excerpt) "repositories": [ { "type": "path", "url": "../php-management-api-client", "options": { "symlink": true } } ]Using
"symlink": truecreates a symbolic link, so changes in the library are reflected without needing to reinstall. -
Require a development version
Composer must know to use a development branch rather than a stable release. The most reliable way is to require a specific dev branch, e.g.
dev-main:"require": { "storyblok/php-management-api-client": "dev-main" }
Version constraints you may encounter
| Constraint | Meaning |
|---|---|
dev-main | Uses the development version from the main branch (recommended for local development). |
@dev | Allows any development version (dev-main, dev-master, etc.). More flexible but less explicit. |
* | Accepts any version (stable or dev). Not recommended because Composer may pick an unexpected version. |
Updating the local dependency
Run the following command to install or update the local package:
composer update storyblok/php-management-api-client
Best practices
- Keep the local clone clean – Avoid committing temporary debug code.
- Switch back to the Packagist version when development is finished.
- Avoid committing the local path configuration to your repository unless it’s intentional (e.g., for a team‑wide development workflow).
By following these steps, you can seamlessly work on a dependency side‑by‑side with your main project, speeding up development and simplifying debugging.