How to use local packages in Composer: a guide for PHP developers

Published: (December 12, 2025 at 04:07 PM EST)
2 min read
Source: Dev.to

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

  1. Place the library near your project

    ~/Projects/my-project
    ~/Projects/php-management-api-client   ← cloned library

    The folder name does not need to match the package name; only the path must match the URL defined in composer.json.

  2. Add a path repository with symlink option

    // composer.json (excerpt)
    "repositories": [
      {
        "type": "path",
        "url": "../php-management-api-client",
        "options": {
          "symlink": true
        }
      }
    ]

    Using "symlink": true creates a symbolic link, so changes in the library are reflected without needing to reinstall.

  3. 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

ConstraintMeaning
dev-mainUses the development version from the main branch (recommended for local development).
@devAllows 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.

Back to Blog

Related posts

Read more »