Safeguard
Software Supply Chain•

How do you run a private Composer repository in front of Packagist?

Composer checks repositories top to bottom, so you can host your own, switch off packagist.org and control exactly which PHP packages reach your builds.

Safeguard Security Team
4 min read

To control where PHP packages come from, host your own Composer repository, list it in composer.json, and disable packagist.org so builds can only resolve what you serve. Composer checks repositories top to bottom, and by default only Packagist.org is registered.

What does Composer do by default?

Per the Composer repositories documentation, only Packagist.org is registered out of the box, repositories are checked top to bottom, and the first match wins by default. Repositories declared inside your dependencies are not loaded, so a dependency cannot add a source on its own.

That default is why a private package name that also exists on the public registry is worth care. If your internal package has the same name as a public one and the public registry is consulted first, you may fetch the wrong code. Ordering and disabling are your controls.

What repository types can you use?

The docs describe these:

  • composer: a single packages.json with all package metadata, which the page says provides the best performance for self-hosted repositories. The url points to the directory containing the file.
  • vcs: installs from git, svn, fossil or hg. Private git repositories need SSH keys.
  • path: a local directory, symlinked where possible.
  • artifact: ZIP or TAR archives from a folder, each with a composer.json in its root.
  • package: one package defined inline. The docs advise against it where possible because Composer will not update it unless the version changes.

For a shared team repository, the composer type is the usual fit.

How do you build one?

The docs name two tools. Satis is a static generator that builds a packages.json from the packages listed in its own composer.json. Private Packagist is a hosted or self-hosted private package host that can also mirror GitHub and Packagist.org. Both are named by the docs, and we have not compared them here.

With a static repository, you control publication: a package appears only after someone reviews it and regenerates the index. That review gate is the point of the exercise.

We did not find a section on mirroring or proxying in the page we read, so check the Satis and Private Packagist documentation for how each handles mirrored packages.

How do you block the public registry?

In a project, add {"packagist.org": false} to the repositories array in composer.json. Globally, run:

composer config -g repo.packagist.org false

Once the public registry is off, every package must come from a repository you listed. A constructed example: a developer adds a new dependency and the install fails with a not found error. That is the control working. They request the package, a reviewer checks it, and it is added to your repository.

What does this not solve?

It does not make the packages safe. Anything you mirror can still contain a flaw or malicious code, so combine the gate with composer audit and review of composer.lock changes. It also adds work: someone has to approve and update packages, and stale mirrors mean slow security fixes.

What to do

  1. Decide who approves new packages and write the criteria.
  2. Stand up a composer type repository with Satis or another host.
  3. Add the repository to composer.json and disable packagist.org in the project.
  4. Keep composer.lock committed and deploy with install, so versions stay fixed.
  5. Run composer audit against the lock file in CI.
  6. Put a time limit on approvals so security updates are not stuck in a queue.
  7. Test the failure path: remove the access you grant to Packagist and confirm builds fail loudly.

Safeguard can scan the dependencies that go into your PHP builds and enforce policies and gates before release, which pairs with the mirror's approval step.

Quick check

Can a dependency add its own Composer repository?

According to the docs, repositories declared in dependencies are not loaded, so only the ones in your root project count.

Does disabling packagist.org make installs safer?

It narrows where packages come from. It does not vet the packages you serve, so keep auditing.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.