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.
composer.lock
should never be added to the Git repo, NEVER. The right approach is to use composer update on staging and then synch the file into production (if everything works, of course). Staging must be the exact copy of a production environment. composer.lock
should be part of .gitignore
.
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
Others go along: (checkout and) composer.phar install --dev.
A developer wants newer versions of dependencies: composer.phar update --dev
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
Actually, I would highly recommend AGAINST installing dependencies on the production server.
My recommendation is to checkout the code on a deployment machine, install dependencies as needed (this includes NOT installing dev dependencies if the code goes to production), and then move all the files to the target machine.
Why?
on shared hosting, you might not be able to get to a command line
even if you did, PHP might be restricted there in terms of commands, memory or network access
repository CLI tools (Git, Svn) are likely to not be installed, which would fail if your lock file has recorded a dependency to checkout a certain commit instead of downloading that commit as ZIP (you used --prefer-source, or Composer had no other way to get that version)
if your production machine is more like a small test server (think Amazon EC2 micro instance) there is probably not even enough memory installed to execute composer install
while composer tries to no break things, how do you feel about ending with a partially broken production website because some random dependency could not be loaded during Composers install phase
Long story short: Use Composer in an environment you can control. Your development machine does qualify because you already have all the things that are needed to operate Composer.
What's the correct way to deploy this without installing the -dev dependencies?
The command to use is
composer install --no-dev
This will work in any environment, be it the production server itself, or a deployment machine, or the development machine that is supposed to do a last check to find whether any dev requirement is incorrectly used for the real software.
The command will not install, or actively uninstall, the dev requirements declared in the composer.lock file.
If you don't mind deploying development software components on a production server, running composer install
would do the same job, but simply increase the amount of bytes moved around, and also create a bigger autoloader declaration.
app-1.34.phar
etc). There's a separate mechanism that is notified and decides when to grab that file, where to transfer it to, and then what to do with it. Some teams choose to have the phar unpacked once it's on the server and some teams run it as-is. It's lent a lot of confidence to the stability and reproducibility of our deploys.
Now require-dev
is enabled by default, for local development you can do composer install
and composer update
without the --dev
option.
When you want to deploy to production, you'll need to make sure composer.lock
doesn't have any packages that came from require-dev
.
You can do this with
composer update --no-dev
Once you've tested locally with --no-dev
you can deploy everything to production and install based on the composer.lock
. You need the --no-dev
option again here, otherwise composer will say "The lock file does not contain require-dev information".
composer install --no-dev
Note: Be careful with anything that has the potential to introduce differences between dev and production! I generally try to avoid require-dev wherever possible, as including dev tools isn't a big overhead.
composer.lock
for dev dependencies. You'd simply run composer install --no-dev
, and you'll get only the regular dependencies installed - in fact, Composer will also remove any dev dependencies in this step.
composer.lock
had dev dependencies in it (and potentially affected the versions of non-dev packages) then I'd want to update it to reflect how it would be in production. This also forces you to run composer install --no-dev
in production, as composer install
will error. Technically I think you're right; this isn't required, but it is an extra level of safety, which I like.
dev/tool
and prod/lib:~1.0
. The newest prod/lib is 1.3, but dev/tool also requires prod/lib:1.1.*
. Result: You will install version 1.1.9 (newest of 1.1.x branch) and use it during your development. I would say it is NOT safe to just update --no-dev
, thus include the newest prod/lib 1.3 and assume everything works without testing. And maybe testing is then impossible because of the lack of dev/tool. I would assume that because dev/tool is not needed in production, it should not be rolled out, but the software must use prod/lib 1.1.9 then.
--no-dev
then you need to test it locally, as I mentioned in the answer. I'd still recommend not using --no-dev
at all though.
composer update
, then do some development, then do composer update --no-dev
, then do the release testing, then push to production and do composer install --no-dev
. Two problems: 1. I cannot test the release without dev dependencies, and 2. I cannot install with for example Git in production.
I think is better automate the process:
Add the composer.lock file in your git repository, make sure you use composer.phar install --no-dev when you release, but in you dev machine you could use any composer command without concerns, this will no go to production, the production will base its dependencies in the lock file.
On the server you checkout this specific version or label, and run all the tests before replace the app, if the tests pass you continue the deployment.
If the test depend on dev dependencies, as composer do not have a test scope dependency, a not much elegant solution could be run the test with the dev dependencies (composer.phar install), remove the vendor library, run composer.phar install --no-dev again, this will use cached dependencies so is faster. But that is a hack if you know the concept of scopes in other build tools
Automate this and forget the rest, go drink a beer :-)
PS.: As in the @Sven comment bellow, is not a good idea not checkout the composer.lock file, because this will make composer install work as composer update.
You could do that automation with http://deployer.org/ it is a simple tool.
composer.lock
will make composer install
act like composer update
. So the versions you deploy are not the ones you developed with. This is likely to generate trouble (and more so in the light of the only recently solved security issue with "replace" in Composer). You should NEVER run composer update
unattended without verifying it did not break anything.
On production servers I rename vendor
to vendor-<datetime>
, and during deployment will have two vendor dirs.
A HTTP cookie causes my system to choose the new vendor autoload.php
, and after testing I do a fully atomic/instant switch between them to disable the old vendor dir for all future requests, then I delete the previous dir a few days later.
This avoids any problem caused by filesystem caches I'm using in apache/php, and also allows any active PHP code to continue using the previous vendor dir.
Despite other answers recommending against it, I personally run composer install
on the server, since this is faster than rsync from my staging area (a VM on my laptop).
I use --no-dev --no-scripts --optimize-autoloader
. You should read the docs for each one to check if this is appropriate on your environment.
Success story sharing
--optimize-autoloader
. Consider also--classmap-authoritative
- From the documentation here getcomposer.org/doc/03-cli.md you can see this: "Autoload classes from the classmap only. Implicitly enables --optimize-autoloader" so you can use if you know the classes "are there", which probably should happen in your prod environment unless you generate classes dynamically.optimize-autoloader
directly in thecomposer.json
:{"config": { "optimize-autoloader": true } }