PHPackages                             compostore/composer-store - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. compostore/composer-store

ActiveComposer-plugin[Utility &amp; Helpers](/categories/utility)

compostore/composer-store
=========================

A pnpm-inspired global store for Composer packages — share packages across projects, save disk space.

v0.0.1-beta.1(2mo ago)01MITPHPPHP ^8.1

Since Feb 26Pushed 2mo agoCompare

[ Source](https://github.com/CompoStore/composer-store)[ Packagist](https://packagist.org/packages/compostore/composer-store)[ RSS](/packages/compostore-composer-store/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (4)Versions (2)Used By (0)

 [![CompoStore icon](assets/compostore-icon.svg)](assets/compostore-icon.svg)

CompoStore
==========

[](#compostore)

> **⚠️ Early Development — MVP Testing Phase**This project is under active development and is currently being tested as an MVP. APIs, behaviour, and file formats may change. Not recommended for production use yet. Feedback and bug reports welcome.

---

> A pnpm-inspired global store for Composer packages. Share packages across projects. Stop duplicating `vendor/`.

---

The Problem
-----------

[](#the-problem)

Every Laravel/PHP project has its own `vendor/` directory. With 100 projects, `laravel/framework` is downloaded and stored 100 times. pnpm solved this for Node.js — CompoStore brings the same idea to Composer.

How It Works
------------

[](#how-it-works)

```
~/.composer-store/packages/
  laravel+framework@11.0.0/   ← stored ONCE
  filament+filament@3.2.0/    ← stored ONCE

project-a/vendor/laravel/framework/  ← hard linked to store (inode: 269463130)
project-b/vendor/laravel/framework/  ← hard linked to same file (inode: 269463130)
project-c/vendor/laravel/framework/  ← hard linked to same file (inode: 269463130)

```

**Hard links** = same inode, no disk duplication, but each project sees its own copy. `vendor/composer/` (autoloader) is always **per-project** — never shared.

---

Two Ways to Use
---------------

[](#two-ways-to-use)

### Option 1: Composer Plugin (Recommended)

[](#option-1-composer-plugin-recommended)

Add CompoStore to your project and `composer install` works transparently:

```
{
    "require": {
        "compostore/composer-store": "*@dev"
    },
    "config": {
        "allow-plugins": {
            "compostore/composer-store": true
        }
    }
}
```

Then just run `composer install` as usual — CompoStore intercepts library package installs and routes them through the global store automatically.

### Option 2: Standalone CLI

[](#option-2-standalone-cli)

```
git clone https://github.com/CompoStore/composer-store
cd composer-store && composer install

# Install packages for a project
./bin/compostore install /path/to/project

# Check store status
./bin/compostore status

# Prune unused packages
./bin/compostore prune --scan ~/projects --dry-run
```

The current CLI binary name is `compostore`.

---

CLI Commands
------------

[](#cli-commands)

### `compostore install [path] [--no-dev] [--store=PATH]`

[](#compostore-install-path---no-dev---storepath)

Reads `composer.lock`, syncs packages to the global store, and hard links them into `vendor/`.

```
compostore install                 # current directory
compostore install /path/to/project
compostore install --no-dev        # skip dev dependencies
```

Supported dist types: `zip`, `tar`, `tgz`/`tar.gz`, and `path`.

### `compostore status [--store=PATH]`

[](#compostore-status---storepath)

Shows store location, total packages, and disk usage.

```
Store Info
  Location:         /Users/you/.composer-store
  Total packages:   142
  Total size:       1.2 GB

Stored Packages
  ✓ laravel+framework@11.0.0
  ✓ filament+filament@3.2.0

```

### `compostore prune [--dry-run] [--scan=DIR] [--store=PATH]`

[](#compostore-prune---dry-run---scandir---storepath)

Removes packages from the store that are no longer referenced by any project.

```
compostore prune --dry-run --scan ~/projects   # preview
compostore prune --scan ~/projects             # actually remove
```

---

Integration Matrix (10 Projects, Composer Plugin)
-------------------------------------------------

[](#integration-matrix-10-projects-composer-plugin)

All integration fixtures now live under `integration/projects/` (no root `example` folders).

### What the matrix covers

[](#what-the-matrix-covers)

- 10 separate projects using the **Composer Plugin** approach (`compostore/composer-store` in `require`)
- Popular public packages across Symfony, Guzzle, Monolog, Doctrine, Flysystem, and Laravel
- One local private package (`acme/private-toolkit`) installed in `project-05`
- Hard-link verification for shared files (`psr/log`) across projects

### Fixture layout

[](#fixture-layout)

```
integration/
  projects/
    project-01 ... project-10
  private-packages/
    acme-private-toolkit/
  results/
    latest-summary.md

```

### Run the full matrix

[](#run-the-full-matrix)

```
./bin/run-integration-matrix --clean
```

This generates per-project logs in `integration/results/` and a summary file: `integration/results/latest-summary.md`.

### Latest run summary

[](#latest-run-summary)

- Projects tested: **10**
- Successful installs: **10**
- Failed installs: 0
- Total elapsed: **62s**
- Store packages: **41**
- Store size: **14M**
- Private package installed: **yes** (`project-05`)
- Hard link verification (`psr/log`): **verified**

---

Real Laravel Live Smoke Test (Ephemeral)
----------------------------------------

[](#real-laravel-live-smoke-test-ephemeral)

In addition to fixture projects, a live smoke test was executed with two real `laravel/laravel` projects created under `/tmp`, both configured to use CompoStore via Composer Plugin.

### What was validated

[](#what-was-validated)

- Both Laravel projects completed dependency install with CompoStore plugin enabled
- Both apps ran concurrently with `php artisan serve` on separate ports
    - `127.0.0.1:8101`
    - `127.0.0.1:8102`
- Health endpoints returned success on both apps
    - `GET /up` -&gt; `200` on both

### Cleanup

[](#cleanup)

- Both temporary Laravel projects and runtime artifacts were deleted after test completion
- No repository files were changed by this smoke test run

---

Architecture
------------

[](#architecture)

```
src/
  Application.php                 ← Symfony Console bootstrap
  Commands/
    InstallCommand.php            ← compostore install
    StatusCommand.php             ← compostore status
    PruneCommand.php              ← compostore prune
  Store/
    GlobalStore.php               ← manages ~/.composer-store
    PackageDownloader.php         ← syncs package archives/path repos into store (with integrity checks)
    PackageInspector.php          ← detects packages with scripts (copy instead of link)
  Linker/
    VendorLinker.php              ← hard links store → vendor/ (or copies for script packages)
    AutoloaderGenerator.php       ← runs composer dump-autoload
  Parser/
    LockFileParser.php            ← parses composer.lock
  Plugin/
    CompoStorePlugin.php              ← Composer plugin entry point
    IOOutputAdapter.php           ← bridges Composer IO to Symfony Output
  Installer/
    CompoStoreInstaller.php           ← custom installer for Composer plugin
tests/
  Linker/VendorLinkerTest.php
  Parser/LockFileParserTest.php
  Store/GlobalStoreTest.php
  Store/PackageDownloaderTest.php
  Store/PackageInspectorTest.php
bin/
  compostore                          ← CLI entry point
  run-integration-matrix          ← 10-project Composer plugin test runner
integration/
  projects/                       ← 10 integration fixture projects
  private-packages/               ← local private package fixture
  results/                        ← matrix logs + summary output

```

---

How the Composer Plugin Works
-----------------------------

[](#how-the-composer-plugin-works)

1. User adds `compostore/composer-store` to their project's `composer.json`
2. `composer install` installs CompoStore and its dependencies first (normal Composer flow)
3. Plugin activates and registers a custom installer (`CompoStoreInstaller`)
4. All subsequent `library` type packages go through the store:
    - **Sync phase**: package is downloaded/extracted (or copied for `path` repos) to `~/.composer-store/packages/`
    - **Install phase**: files are hard linked from store into `vendor/`
5. On re-install: packages already in the store are linked instantly (zero downloads)

---

Known Limitations
-----------------

[](#known-limitations)

- Source-only VCS installs (no dist archive URL) fall back to Composer's default installer
- Packages with `scripts` in their `composer.json` are copied, not hard-linked (safe but uses extra space)
- Windows not yet supported
- No parallel downloads (sequential)
- Plugin's own dependencies (symfony/console, etc.) install via Composer's default flow

---

Roadmap
-------

[](#roadmap)

PhaseStatusGoal1DoneCLI MVP — `install`, `status`, `prune`2DoneComposer Plugin — transparent `composer install` integration3DoneIntegrity checks, post-install script safety, PHPUnit test suite4PlannedWindows support, Packagist release, parallel downloads---

Tech Stack
----------

[](#tech-stack)

- PHP 8.1+
- Symfony Console 6/7
- Composer Plugin API 2.0
- PHPUnit 10+

AI-Assisted Development
-----------------------

[](#ai-assisted-development)

This project was initially generated and developed with the assistance of [Claude](https://claude.ai) (Anthropic) and [Codex](https://openai.com/blog/openai-codex) (OpenAI).

AI tools were used throughout: architecture design, code generation, and documentation. All code has been reviewed, tested, and is maintained by human developers. The ideas, decisions, and responsibility for this software remain with the authors.

---

License
-------

[](#license)

MIT

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance85

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity28

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

79d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9499120912b47a170291b3b795ea0255f060d8500bd2988535e4e6faccee5c8d?d=identicon)[solutionforest](/maintainers/solutionforest)

---

Top Contributors

[![solutionforestteam](https://avatars.githubusercontent.com/u/53035878?v=4)](https://github.com/solutionforestteam "solutionforestteam (5 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/compostore-composer-store/health.svg)

```
[![Health](https://phpackages.com/badges/compostore-composer-store/health.svg)](https://phpackages.com/packages/compostore-composer-store)
```

###  Alternatives

[vaimo/composer-patches

Applies a patch from a local or remote file to any package that is part of a given composer project. Patches can be defined both on project and on package level. Optional support for patch versioning, sequencing, custom patch applier configuration and patch command for testing/troubleshooting added patches.

2994.3M16](/packages/vaimo-composer-patches)[php-soap/wsdl

Deals with WSDLs

173.5M12](/packages/php-soap-wsdl)[altis/local-server

Local Server module for Altis

18208.4k2](/packages/altis-local-server)[vaimo/composer-changelogs

Provide information about package changes based on changelog files that are bundled with releases; provide tools for generating documentation files from changelog sources

11150.5k10](/packages/vaimo-composer-changelogs)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[uma/composer-psysh

No-frills PsySH-Composer plugin

183.2k](/packages/uma-composer-psysh)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
