Learn more about Russian war crimes in Ukraine.

How do I release a PHP Composer package?

Composer is the standard package manager for PHP. Here’s how to release a package for it.

First let’s clarify what I’m doing. I have an example project called donut-news, and its composer.json looks like this:

    "name": "jameshfisher/donut-news",
    "description": "Donut news",
    "type": "project",
    "authors": [
            "name": "Jim Fisher",
            "email": "jameshfisher@gmail.com"
    "require": {
        "monolog/monolog": "^1.23"

The require block defines the dependencies for jameshfisher/donut-news, and currently it has one dependency: monolog, a logging library. This dependency was added by running:

php composer.phar require monolog/monolog

Now donut-news has a lot of donut logic which would be better put in a generic donuts library. I want to create a new Composer library package called donut-logic, so that I can add it to my donut-news project by running

php composer.phar require jameshfisher/donut-logic

When you run php composer.phar require foo/bar, Composer looks for the package foo/bar in repositories. A repository is a store of Composer packages. The default Composer repository is https://packagist.org, and you can browse all the packages on Packagist.org here. To release jameshfisher/donut-logic, I need to get it into this list.

Composer package names are prefixed with a “vendor” name. In jameshfisher/donut-logic, the vendor is jameshfisher. On Packagist.org, vendor names correspond to accounts. I created an account on Packagist.org called jameshfisher.

Packages on Packagist.org are backed by git repositories. I created a new repository at https://github.com/jameshfisher/donut-logic.

Just like your PHP projects have a composer.json, Composer packages/libraries also have a composer.json. I created this composer.json for donut-logic, and added it to the root of the repository:

    "name": "jameshfisher/donut-logic",
    "description": "Shared logic related to donuts",
    "require": {}

Next, I visited https://packagist.org/packages/submit, which asks for the repository URL. I submitted it, and it registed a new Packagist.org package: https://packagist.org/packages/jameshfisher/donut-logic. However, this new package is not “stable”, so can’t be installed by default!:

$ php composer.phar require jameshfisher/donut-logic

  Could not find package jameshfisher/donut-logic at any version for your m
  inimum-stability (stable). Check the package spelling or your minimum-sta

It turns out that “stable” means “has a git tag”. So I tagged my current version as 0.0.1:

$ git tag 0.0.1
$ git push --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:jameshfisher/donut-logic.git
 * [new tag]         0.0.1 -> 0.0.1

This isn’t enough, because Packagist.org doesn’t know that I’ve updated the source git repository. I need to tell it that the repository has been updated:

curl \
  -X POST \
  -H 'Content-Type: application/json' \
  -d '{"repository":{"url":"https://github.com/jameshfisher/donut-logic"}}' \

(I got my Packagist.org API token at https://packagist.org/profile/.) Now at https://packagist.org/packages/jameshfisher/donut-logic I can see that there are two versions of my package: dev-master and 0.0.1. I can now require my package, and it gets version 0.0.1:

$ php composer.phar require jameshfisher/donut-logic
Using version ^0.0.1 for jameshfisher/donut-logic
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing jameshfisher/donut-logic (0.0.1): Downloading (100%)
Writing lock file
Generating autoload files

There’s a more reliable way to ensure that Packagist.org is up-to-date with the source git repo: GitHub Service Hooks. I went to https://github.com/jameshfisher/donut-logic/settings/hooks/new?service=packagist, and configured it with my username and Packagist.org API token. Now, when my repository is updated, GitHub will notify Packagist.org.

What can computers do? What are the limits of mathematics? And just how busy can a busy beaver be? This year, I’m writing Busy Beavers, a unique interactive book on computability theory. You and I will take a practical and modern approach to answering these questions — or at least learning why some questions are unanswerable!

It’s only $19, and you can get 50% off if you find the discount code ... Not quite. Hackers use the console!

After months of secret toil, I and Andrew Carr released Everyday Data Science, a unique interactive online course! You’ll make the perfect glass of lemonade using Thompson sampling. You’ll lose weight with differential equations. And you might just qualify for the Olympics with a bit of statistics!

It’s $29, but you can get 50% off if you find the discount code ... Not quite. Hackers use the console!

More by Jim

Tagged #programming, #php. All content copyright James Fisher 2017. This post is not associated with my employer. Found an error? Edit this page.