Project Repository Best Practice

How to use one git repository for your project and (site) package(s) while using composer.

– Written by

An updated version of this great content can be found in the Neos Docs.

Go to the docs

In order to ease integration of Neos within the composer eco-system we wanted to provide a solution for typical Neos projects to use a single git repository for developing multiple packages while fully embracing composer.

The "Path Repository" Setup

To avoid problems with composer we propose a setup where the site package - and other project specific packages - is included in the repository but outside the "Packages" folder. It is then required via composer and a "path" repository type.

All packages you want to version together with the project distribution go to the "DistributionPackages" folder. You then need to tell composer where these packages are in the "repositories" part of your root manifest ("composer.json".)

Since your distribution packages do not have a version of their own–as they are in the same repository as the distribution–you need to require them as "@dev".

An example repository showing how the configuration should look like can be found here:

    "name": "vendor/your-project-distribution",
    "description": "Describe your project here",
    "config": {
        "vendor-dir": "Packages/Libraries",
        "bin-dir": "bin"
    "require": {
        "test/site": "@dev"
    "repositories": {
        "distribution": {
            "type": "path",
            "url": "./DistributionPackages/*"
    "scripts": {
        "post-update-cmd": "Neos\\Flow\\Composer\\InstallerScripts::postUpdateAndInstall",
        "post-install-cmd": "Neos\\Flow\\Composer\\InstallerScripts::postUpdateAndInstall",
        "post-package-update": "Neos\\Flow\\Composer\\InstallerScripts::postPackageUpdateAndInstall",
        "post-package-install": "Neos\\Flow\\Composer\\InstallerScripts::postPackageUpdateAndInstall"

With this configuration your "test/site" package is installed via composer despite being in the same repository. Therefore composer picks up all dependencies of your site package.

We like this setup and consider it best practice for Neos projects since a while. That also means we will in turn adapt our distributions as well as tools to make use of such a setup. Take note that in a future Neos version we might remove suppport for the old type of setup and only rely on composer for installing packages.

If you are interested to read about the actual problems this setup solves, read below.

Screenshot 2018-11-08 at 15.02.03.png

best practice project repository

The Classic Setup

The classic (or old as we called it above) Neos project contains a site package together with the root manifest and configuration (what is called a distribution) as seen on the right.

This works for Neos as we check the "Packages" folder for any packages in addition to composer installed packages. 


Screenshot 2018-11-08 at 11.02.49.png

"old" style project repository

This setup has some drawbacks though, that we solve by our proposed best practice solution:

  1. You need to un-ignore parts of the "Packages" folder in git. While this is perfectly fine it can easily end up in a convoluted and messy ignore file. With the best practice solution you can ignore the whole "Packages" folder.

  2. The package is never actually installed via composer, which means that dependencies inside that package will not be resolved by composer. But they are still needed to make sure Flow orders the packages according to the dependencies, effectively meaning you have to duplicate the dependency declararations in your root AND package manifest. This is all avoided with the best practice setup, dependencies only exist in your site package(s) and everything is loaded by composer.

  3. Additionally Flow has to take care of autoloading these packages. As we cannot know which packages are installed via composer, Flow basically replicates composers autoloader with runtime logic which is slow and error prone. This also leads to problems with running tests in these packages. You can again circumvent the problem by duplicating the autoload declarations in your package and the root composer.json. Any other composer specific logic or mechanic is obviously also never applied to your package. This might give you addditional problems that you may not have noticed so far. As with 2) this is solved by the best practice setup because everything is loaded by composer.