Exploration: Composer Path Repositories for Local Drupal Module Dependencies
The Hook When one Drupal module depends on another, I want to iterate across both without publishing interim versions or wiring up a private Composer repo. Path repositories give me that speed while keeping dependency boundaries honest.
Why I Built It I explored how Composer path repositories can simplify local Drupal module development when one module depends on another. The goal is to iterate across modules without publishing interim versions or wiring up a private Composer repo, while still mimicking production resolution.
The Solution
Why Path Repositories Work Well for Drupal
Drupal modules are Composer packages. If module-a requires module-b, you can point the consuming site to a local checkout of module-b during development, while keeping production on a tagged release. This keeps module boundaries clean and mirrors how dependency resolution will behave in production.
Minimal Setup (Composer Root)
Add a path repository entry in the project's root composer.json:
{
"repositories": [
{
"type": "path",
"url": "../modules/module-b",
"options": {
"symlink": true
}
}
]
}
Then require the package as normal:
composer require vendor/module-b:@dev
With symlink: true, changes in module-b are immediately visible to the consuming project.
Module Composer.json (Dependency Side)
In module-a/composer.json, declare the dependency normally:
{
"require": {
"vendor/module-b": "^1.2"
}
}
During development, the path repository overrides that constraint with your local checkout. In production, Composer resolves to the tagged version from the main repo.
Workflow Notes
- Keep package names and versions consistent across module repos so resolution behaves as expected.
- Use
@devonly in the root project, not in module repositories, to avoid leaking dev constraints into releases. - If you need to test multiple dependency branches, switch the local checkout and run
composer update vendor/module-bto refresh the lock file.
Common Pitfalls
- If
module-bisn't a valid Composer package (missingcomposer.jsonorname), the path repo won't resolve. - If symlinks aren't supported (some CI environments), set
symlink: falseor omit the option. - If you forget to remove the path repository before releasing the site, you can accidentally pin to a local path in
composer.lock.
The Code I built a small Drupal module dependency demo that shows the path repository setup end to end. You can clone it, run through the Composer workflow, and browse the key files here: View Code
What I Learned Path repositories are a clean way to keep Drupal module dependencies modular while still enabling fast local iteration. They mirror production resolution closely, but only if you keep package metadata consistent and avoid dev constraints leaking into module releases.
Why this matters for Drupal and WordPress
Composer path repositories are essential for Drupal module developers working on interdependent contrib or custom modules — the pattern shown here prevents the need to publish interim releases during active development. WordPress developers increasingly use Composer via tools like Bedrock and Sage; the same path repository technique applies when developing WordPress plugins or themes that depend on shared PHP libraries, making this a cross-CMS development workflow worth adopting.
References
- Using Composer Path Repositories to Handle Module Dependencies During Development
- Composer path repository documentation
Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.
