How to deploy correctly when using Composer's develop / production switch?

Sliq picture Sliq · Feb 12, 2014 · Viewed 150.6k times · Source

Composer has the option to load several dependencies only while being in development, so the tools will not be installed in production (on the live server). This is (in theory) very handy for scripts that only make sense in development, like tests, fake-data-tools, debugger, etc.

The way to go is to add an additional require-dev block with the tools you need in dev:

"require-dev": {
    "codeception/codeception": "1.6.0.3"
}

and then (theoretically) load these dependencies via

composer install --dev

Problem & Question:

Composer has changed the behaviour of install and update dramatically in 2013, require-dev-dependencies are now installed by default (!), feel free to create a composer.json with a require-dev block and perform an composer install to reproduce.

As the most accepted way to deploy is to push the composer.lock (that holds your current composer setup) and then do an composer install on the production server, this will also install the development stuff.

What's the correct way to deploy this without installing the -dev dependencies ?

Note: I'm trying to create a canonical Q/A here to clarify the weird Composer deployment. Feel free to edit this question.

Answer

Jasper N. Brouwer picture Jasper N. Brouwer · Feb 20, 2014

Why

There is IMHO a good reason why Composer will use the --dev flag by default (on install and update) nowadays. Composer is mostly run in scenario's where this is desired behavior:

The basic Composer workflow is as follows:

  • A new project is started: composer.phar install --dev, json and lock files are commited to VCS.
  • Other developers start working on the project: checkout of VCS and composer.phar install --dev.
  • A developer adds dependancies: composer.phar require <package>, add --dev if you want the package in the require-dev section (and commit).
  • Others go along: (checkout and) composer.phar install --dev.
  • A developer wants newer versions of dependencies: composer.phar update --dev <package> (and commit).
  • Others go along: (checkout and) composer.phar install --dev.
  • Project is deployed: composer.phar install --no-dev

As you can see the --dev flag is used (far) more than the --no-dev flag, especially when the number of developers working on the project grows.

Production deploy

What's the correct way to deploy this without installing the "dev" dependencies?

Well, the composer.json and composer.lock file should be committed to VCS. Don't omit composer.lock because it contains important information on package-versions that should be used.

When performing a production deploy, you can pass the --no-dev flag to Composer:

composer.phar install --no-dev

The composer.lock file might contain information about dev-packages. This doesn't matter. The --no-dev flag will make sure those dev-packages are not installed.

When I say "production deploy", I mean a deploy that's aimed at being used in production. I'm not arguing whether a composer.phar install should be done on a production server, or on a staging server where things can be reviewed. That is not the scope of this answer. I'm merely pointing out how to composer.phar install without installing "dev" dependencies.

Offtopic

The --optimize-autoloader flag might also be desirable on production (it generates a class-map which will speed up autoloading in your application):

composer.phar install --no-dev --optimize-autoloader

Or when automated deployment is done:

composer.phar install --no-ansi --no-dev --no-interaction --no-plugins --no-progress --no-scripts --optimize-autoloader

If your codebase supports it, you could swap out --optimize-autoloader for --classmap-authoritative. More info here