Using Composer and Satis to handle private php repositories

Using Composer and Satis to handle private php repositories

Composer is an awesome and powerful tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them, and their respective dependencies for you. To make your own libraries or packages usable by composer users, you need to declare them towards composer. When the package is public, less steps are required. You could host your repository online on GitHub for example, then declare it towards the index for example. When the repository is private, it's a bit trickier, and I spent some time figuring it out, so here's a little feedback on my attempts.

Thank You for Downloading

I'm glad that you found my work useful. If you did, it might help some other people too. So why not helping me spread the word with a tweet? You could also buy me a coffee to thank me for my code and explanations if you prefer ;).
I hope you'll enjoy your download. Regards. Jeremy.

Getting started

As an organisation producing a handful of quality handmade sites per year, we quickly felt the need to capitalize on some core functionalities. Even though some of them were public or open sourced, such as our wonderwp framework for example or the pew.js library, some others required to be kept private.

Composer is at the heart of our build processes, we use it to easily manage our dependencies so we wanted our private plugins to be managed with it too. The first thing we therefore did at the time was to look at the official composer documentation regarding private repositories. Here's a summary of what I found relevant in our case:

  • By default, when you require a dependency, composer will look for it in its own packagist index. If your library or repository is not in this index, which will be the case for private repositories, then you have to tell composer where to find it thanks to the repositories section in your composer.json file.
  • You have the choice between different types of repositories, but more precisely in our case we're looking at vcs or composer. In other words, either you add a vcs entry per private dependency in your composer.json file so composer will know where to find your private repos, or you create your own private composer.
  • For our projects, we typically have more or less 6 to 10 private dependencies to add. So by choosing the vcs way of doing, we'd need to add as much vcs entries by hand as we have private dependencies. You can see the example here. Those vcs entries need to have a full GitHub path, and the machine making the composer install call need to be authenticated with GitHub via its ssh key to be authorized to pull the packages. As you can see that's quite some manual work to do, and this work is proportional to the (growing) list of our private packages. Surely there must be a better way.
  • This better way seems to be the other type called composer. I don't know if you tried to read the paragraph in the official documentation but then I did I felt a bit confused. It did feel like what we were looking for though so I decided to try it out.

Trying out to make a private composer index

Like I said, when I first read the documentation, I was left a bit confused. So I thought I'd figure it out by doing. Okay so first we need to create a packages.json file. We'll put in this file all the private repositories information, then we'll reference this file in our composer.json file to make composer aware of our private repos.

The thing that then caught my eye was what they called the minimal package definition, and that looks like this.

  1. {
  2. "name": "smarty/smarty",
  3. "version": "3.1.7",
  4. "dist": {
  5. "url": "",
  6. "type": "zip"
  7. }
  8. }

What I understand from this is something like : "Composer, if we're trying to require smarty/smarty at version 3.1.7, you can find the zip here :". The dist part can also be an hosted git repository url, and that's probably more the case with living proprietary private packages.

So to build our packages.json file, we should pile up a list of package definitions. For each private library we want to use, we should add one package definition per version number (and there could be quite a lot of them)

Some notable difference with vcs repos versus zips, is that you also need to provide in the dist part, a reference number, which is actually the commit id. And that's very important because keeping that reference accurate and up to date plus the fact that we need to have one package definition per library version make up the fact we'll need a tool such as private packagist or satis to automate this packages.json build, and therefore make this composer option truly viable.

Without automated solution, you'd have to go back to edit your packages.json file every time you add a new version to one of your repositories, and even worse, every time you add a new set of commits to any version to update this version's reference number. That's truly not acceptable to do all this by hand.

Automating the build

I looked for a solution to automate the packages.json build, and by looking at different resources around the internet, there are quickly two players that often come back: private packagist and satis. At the time of my investigations private packagist was just released, and was not free for an organisation like ours. I therefore decided to give satis a try because I also must say that I quite like to tackle those kind of industrilasation challenges, made of investigations and trials and errors.

Private packagist was founded by Jordi Boggiano and Nils Adermann, the creators of Composer. They put in some regular efforts to propose a product that helps packages maker to host their private repos just like you would do on the open source, which is exactly the point of this article. Therefore you should pay them a visit to see if the quality of their services would actually be a more interesting alternative for you than building it on your own.

If you're adventurous like me then read on :)!

Installing Satis

Like explained in the satis documentation, to install satis you need to run : composer create-project composer/satis:dev-master --keep-vcs, and follow up the command prompt.

The satis command

Satis can be invoked like so: php bin/satis build <configuration-file> <output-dir>

As you can see you have three parts in this command. Firstly you need to provide the path to your satis executable, then you need to specify which configuration file you'd like to use (typically the satis.json file we'll talk about in the next paragraph), and finally a folder output where it will generate all the necessary files for your private composer to run, the packages.json file being one of them. But it will also generate a webpage presenting all of your available packages, their available version number and so on.

The output directory should then be made accessible online so we can use its url inside our project composer.json file, within the repositories section. In order to avoid https warnings, it's better to setup https on the url you're going to use, for example :

The satis.json file

This file is there to help you configure satis, mainly to tell him where to find your private packages so it can work with them. The documentation explains the available options. In mine, I've listed all of my private packages GitHub urls, and I've specified that I want to build every branch satis will find in them through the option named "require-all": true. You can find my satis.json file attached to this article.

We are now at a point where we have a satis command ruled by a proper statis.json file, that generates our private composer index. But we still have a manual step that is to launch the satis command every time we want to update our index. The ideal would be to automate the launch of the command every time we commit to any of our repositories.

To achieve this, we need to prepare a script that would then be called via GitHub webhooks (or equivalent), every time we push new commits or new version tags, and the job of this script would be to execute the satis build command to regenerate our private composer index.

The update script

I've attached an update script inside the zip file that accompanies this article.

Let's see how you can configure it. Line 9 you have a $config array where you need to specify where your satis executable is located (that's the very first part of the statis build command), where your satis.json file is (that's the second part), and where you want the packagist index to be build, (that's the third part).

That's the only thing you should need to configure. Those arguments will be used to invoke the satis build command that the script will then execute for you.

Executing the update can be quite long, and this fact gives us two conclusions.

  • Firstly, there's no point rebuilding the entire index with all of your private packages if you only sent a push to one of them. We should consider setting up a partial rebuild.
  • Secondly, as you don't really know how long it will take, it's nice to setup some sort of notification in place so you know when the script ends. That's important because this end is the signal that you can now do a composer update from within your project to get the latest changes from your private packages.


Put the update script online where it can be accessed via a url, for example We'll use this url as a target for our webhooks.

In GitHub, to setup a webhook, you need to go to one of your repositories, then in settings / webhooks, add a new webhook, then specify that on the push event you'd like to make a request to your remote update script url at

Considering partial rebuilds, depending on how the webhook is setup, we can therefore know in the update script which repository is concerned, and only rebuild the index parts that are relevant. When pushing commits to a repository, this could mean we added some commits to an existing version number, or that we've created a new version number.

Satis has an option named --repository-url which can be used to tell it to only concentrate on scanning this one and only repository. We've paired our webhooks with this option so that all the webhooks carry the repository name in a special parameter, for example : In case of GitHub webhooks, you might not need to pass parameters in the url because it posts you a json payload with all this information as well. The aim is that when the update script receives the webhook it should know which repository url it should update. This improvement made our script 20 times quicker to execute (because we've had around 20 private repositories at the time) so as you can see it's a huge performance improvement.


When the update script first ran, I was sure it was triggering properly thanks to webhooks, but when I had no idea if it had finished, or if it was still running. So I tried my luck by running composer update in my project and one times out of two, it either served me the 'nothing to update or install' sentence, or it started updating or installing the updated dependencies.

To avoid this waiting game, I setup a slack notification in a dedicated channel that warned everyone following this channel that one package index had been updated and was available to everyone. That was much much better, I definitely encourage you to do something similar within your own communicate medium.

Referencing your private packagist inside your projects

Now that you have a private composer index accessible online somewhere, open up your project composer.json file, and locate the repositories section. Then add up an entry of type composer with your index url like so:

  1. "repositories": [
  2. {
  3. "type": "composer",
  4. "url": ""
  5. },
  6. {
  7. "type": "composer",
  8. "url": ""
  9. }
  10. ]


Hosting your own private packagist can be quite challenging if you've never done it before. I hope this little guide would help make the process easier. For example, as I wasn't a composer specialist, it took me a few bunch of days of investigation, trial and errors before getting to a setup that was production ready. That can be seen as quite an investment. I do hope that you'll go quicker than me thanks to this article though :) .

And once you've got the whole thing running, for your developers it will be so much easier to use the private repositories. Apart from the additional line to put inside the repositories section of your project, requiring private dependencies would be nearly as straightforward as public ones. And that's the whole point of all this really.

8 Responses to Using Composer and Satis to handle private php repositories

  1. I know this site gives quality depending posts and additional data, is there any other site
    which gives these kinds of stuff in quality?

  2. Have you ever thought about writing an ebook or guest authoring on other
    blogs? I have a blog based upon on the same information you discuss and would love
    to have you share some stories/information. I know my audience
    would appreciate your work. If you are even remotely interested, feel free to shoot me an e mail.

  3. Hi, I have a cuestion with my git repository and the users when I do composer. I have a module in a private git repository on my server. This module I sale in my website, and when a user buy it i want to create for this user a credentials (user and password) to he can install the module using composer (composer require vendor/module-name). How can I create credentials for each user that buys my module so they can only install it. I need to known what steps I have to folow to create a composer module with credentials.

  4. Excellent items from you, man. I've be aware your
    stuff prior to and you are simply extremely wonderful. I really like what you've
    received right here, really like what you're stating and the way in which during which you say it.
    You're making it entertaining and you still care for to keep
    it smart. I can't wait to read far more from you.
    That is actually a wonderful web site.

  5. Having read this I believed it was rather
    enlightening. I appreciate you taking the time and effort to put this information together.
    I once again find myself personally spending
    way too much time both reading and leaving
    comments. But so what, it was still worth it!

  6. This post was amazing i actually read your blog fairly often, and you're
    always coming out with soome great stuff. I embedded this on my fb, and my followers realpy liked it.
    I really aadmire the very god work :)

  7. This paragraph presents clear idea for the new people of blogging, that
    genuinely how to do blogging.

  8. Thiis post was amazing i try to read your blog fairly often, and you're consistently coming
    out with a lot of great stuff. I embedded tbis on my blog,
    and my fopllowers really lioked it. Continue the great work :)

Leave a Reply

Your email address will not be published. Required fields are marked *

Other Useful Resources

How to easily integrate a PayPal Checkout with PHP illustration

PayPal is a renowned payment platform that allows you to accept online payments on your site, by taking care of all the money transactions for you. This transparency really is an appreciated quality that allows developers to integrate checkout solutions on merchant sites, by completely outsourcing the banking operations to PayPal.

Another good thing for developers is that the PayPal API is very versatile. It can be very simple if your needs are simple, or it can be very well customized to meet some more advanced needs such as complete shopping carts handling. On the other hand, I sometimes find this API not really user friendly as it works with forms, which fields are not always very intuitive. In other words, depending on the form you are building, you get a different service from PayPal.

In order to get a friendlier and also more generic solution, I wrote a PayPal manager in PHP. This tutorial will show you how you can benefit from this PHP class to integrate PayPal checkouts faster and in a much simpler way.

Read more
Form Cloning jQuery Plugin illustration

Building dynamic forms is a task that a lot of web developers will have to do at some point. By dynamic I mean forms that change based on what the user inputs.

A basic example of dynamic forms, are those that allow the user to add the same group of information several times. For example, an attendance form, where you can add several persons, a booking form where you can add several tickets, a membership with several users, a media page with several pictures or videos and so on, the possibilities are countless.

In order to facilitate the development of such forms, I created a little plugin, that allows you to dynamically clone a specific set of information that will be repeated. So if you ever searched a way of cloning forms, fieldsets or groups of input, this could really be helpful.

Read more
jQuery FancyBox plugin illustration

The FancyBox is one of the plugin that I like the most. It's so easy to use and renders really nicely, especially with images. It's a Mac like zooming tool that you can customize quite well and really looks amazing. Source and © Janis Skarnelis

Read more
@jeremypetrequin Ok tu build spécifiquement ce fichier scss pour avoir un fichier css que tu peux charger pour ton bloc en BO donc. Merci.22 May / 14:21