The ultimate Magento 2 build & deploy commands workflow

Magento 2 is the second version of the most used eCommerce platform in the world. As of 2018, Magento is part of the Adobe family. M2, as we like to call it, is more powerful than its predecessor, and brings a long list of features. But it is also much more difficult to configure and deploy, compared to Magento 1.
Why is that, you ask? In order to increase modularity and convenience during the development lifecycle, the Magento 2 team decided to add a few compilation steps for code, themes, etc., which are mandatory to execute when running on production. As a result, deployment takes longer and requires proper orchestration to avoid as much as possible any maintenance mode and downtime during it.
Magento 2 now also uses the Composer to manage modules and dependencies. It also introduced a configuration management mechanism in order to maintain consistent, shared, and scoped settings across environments. These are definitely amazing features, but they do complicate things when it comes to deployment.
There are plenty of articles out there on Magento 2 deployment but most of them are either outdated, or they focus on one specific deploy part (only static, for example). There is also no single way to deploy a Magento 2 app. But we do believe we have a secret recipe. Working every day with customers, we have spent countless hours trying to find the best and fastest way to build and deploy a Magento 2 app in the cloud.
So, we created the most optimized and complete workflow—from importing code to setting up the URL, you have all the steps in a single blog post!
In this workflow, we’ll show you how to:
- make a Magento 2 app as fast as possible
- use less memory (Maximum 8Go—we see you, Composer)
- reach almost zero downtime
- make a Magento 2 work for single servers and multi-servers (It’s 2021, production environments should not running on a single instance!)
- correctly update and refresh cache
- break down the app into build & deploy stages (based on the containers philosophy)

Note: This workflow is applicable to all Magento 2 projects using version 2.2.5 and later and it needs to be adapted only if you change the core behavior of Magento 2. Use this workflow to deploy Magento 2 apps in a production environment. Some of the steps you’ll see here are not necessary if you deploy an app in staging, dev, or local environments.
How to build a Magento 2 application
The build stage is a transform which converts a code repo into an executable bundle known as a build. Using a version of the code at a commit specified by the deployment process, the build stage fetches vendors dependencies and compiles binaries and assets.
The twelve-factor app
To get things started, you need a Dockerfile with all the Magento 2 requirements (extension, PHP, web server configuration, etc.). If you don’t have one, you can use our Base Magento Dockerfile.
Now, let’s dig in!
1. Download code
git clone --recurse-submodules [email protected]:artifakt-io/base-magento.git
COPY --chown=www-data:www-data $CODE_ROOT /var/www/html/
First, we clone the Git repository and all its submodules. Using the $CODE_ROOT
variable, we copy Magento 2 code from the Git repo to the web server document root—in our case, /var/www/html
. This way your code lives directly inside the container for performance and flexibility. Make sure you don’t mount code in the persistent directory.
Note: All actions below are now executed with the www-data
user.
2. Run composer
RUN [ -f composer.lock ] && composer install --no-cache --no-interaction --no-dev || true
If composer.lock
file is present, we run the composer install
command without dev dependencies making sure we are in a production environment. Each build is isolated so we don’t use cache. That’s maybe an improvement for the future. If you need credentials to download your vendors, add an auth.json file at the same location as the composer.lock file.
Note: We don’t run the bin/magento module:enable
command because we recommend that you version the app/etc/config.php
file, including the Magento 2 modules you want to enable, and any shared configuration you may want to declare. You can find out more about this here and here.
3. Compile the code
php bin/magento setup:di:compile
This step is pretty simple, we just compile all Magento files and classes into the generated directory. See more here.
4. Dump an optimized composer autoloader
composer dump-autoload --no-dev --optimize --apcu
This command aims to improve the performance of the composer autoloader. The -optimize
option converts PSR-0/4 autoloading to classmap to get a faster autoloader, which is recommended, especially in production. The --apcu
option uses APCu to cache found/not-found
PHP classes. See more here.
5. Deploy static view files
RUN php bin/magento setup:static-content:deploy -f --no-interaction --jobs 5
Finally, we write all static files to the Magento file system. See more here.
Note: We are also considering eventually integrating the compact deploy strategy in the future, in order to improve the build time a bit more, and also save some disk space.
Congrats! Your Magento 2 is now built into a single container and ready for deployment anywhere in the cloud.
How to deploy a Magento 2 application
The deploy or release stage takes the build produced by the build stage and combines it with the deploy’s current config (here the app/etc/env.php file for Magento). The resulting release contains both the build and the config and is ready for immediate execution in the execution environment using environments services, variables and persistent data.
The twelve-factor app
Note: We assume that your Magento is already installed in the environment you want to deploy—all infrastructure services are online and the database is not empty. Also, all commands related to database upgrades and maintenance are only run on the main replica.
6. Mount persistent directories
/pub/media
/pub/static/_cache
/var/
To make sure your production environment is resilient (has high availability), your code needs to run on different servers located in different data centers. We recommend you share persistent data and directories across all these web servers and directories.
In our case, we decided to set up these three directories for Magento 2 by default:
/pub/media
for assets, such as product images/pub/static/_cache
, for compiled and merged CSS and JS files/var
for all files generated by Magento: reports, logs, dataflow files, etc.
7. Define the app/etc/env.php configuration file
mv /app/etc/env.php.$ENV_CODE /app/etc/env.php
In this step, we copy the Magento app/etc/env.php
configuration file related to the current environment ($ENV_CODE
variable). This file includes all configurations and credentials of the different services used by Magento for this environment. It may also contain some settings that are specific to the installation environment.
We recommend you use as many environment variables as possible inside this file to make your release flexible and reliable in case of infrastructure changes. You can see an example here.
8. Enable maintenance mode (if needed)
if [[ "$(bin/magento setup:db:status)" != "All modules are up to date." || "$(bin/magento app:config:status)" != "Config files are up to date." ]]
then
php bin/magento maintenance:enable
fi
In order to avoid downtime, we put Magento under maintenance only if the new release needs to update configuration and/or database schema/data. The var
directory is shared between all releases and all replicas and for this reason, maintenance would be active on all servers/replicas, as well as current and new releases (blue/green deployment).
Note: We are currently considering relying on commands exit codes instead of commands outputs, to securitize a bit.
9. Update database (if needed)
if [ "$(bin/magento setup:db:status)" != "All modules are up to date." ]
then
php bin/magento setup:db-schema:upgrade --no-interaction
php bin/magento setup:db-data:upgrade --no-interaction
else
echo "Database is already up to date."
fi
Magento 2 uses a database schema and data versioning. If a module needs to be upgraded, we run these two commands to update the database.
10. Update configuration (if needed)
if [ "$(bin/magento app:config:status)" != "Config files are up to date." ]
then
php bin/magento app:config:import --no-interaction
else
echo "Configuration is already up to date."
fi
If system configurations for the env.php
and/or config.php
files are different from the current configuration, use the bin/magento app:config:import
command. See more here.
11. Disable maintenance mode (if needed)
maintenanceStatusMsg=$(bin/magento maintenance:status)
maintenanceOnSubstring="Status: maintenance mode is active"
if [ "${maintenanceStatusMsg/$maintenanceOnSubstring}" != "$maintenanceStatusMsg" ]
then
php bin/magento maintenance:disable
fi
For the very last step, make sure you disable maintenance if it was already enabled.
Congrats! Your new Magento 2 release is now online and running smoothly.
About cache management
As you may have noticed, we don’t flush the Magento cache at all during build or deploy steps.
That’s because you don’t really need to do it. Here’s why:
OPcache/APCu
caches are totally empty because it’s a brand new container.- We recommend you set Magento cache prefix ID in your
app/etc/env.php
file, using the build ID, this way each time you build and deploy a new release, the cache is renewed implicitly, as scoped by this new prefix. - We recommend you enable Magento static content signing. It adds the current deployment version in your assets’ URLs each time you deploy a new version of your application. This way, you don’t need to flush your CDN, as the browser cache is invalidated automatically.
To sum up
Using this command workflow, the default Magento 2 code would build in around five minutes. And if you want this to be even faster, consider removing some Magento vendors or modules, as well as some language and theme generations.
Deployment should only take you between 10 and 30 seconds. That’s pretty cool, right? When auto-scaling, you can have a new instance of your Magento 2 application in 15 seconds on average. Keep in mind that this could take longer if you have some database upgrades to run.
This process respects container philosophy and could be done on any resilient infrastructure—load balancer with EC2 or Kubernetes with multi-nodes. And last but not least, if there are no database upgrades, it doesn’t imply any downtime!
We hope these commands will help you deploy your Magento 2 eCommerce website faster and easier. Check out our Artifakt Sample Magento App on GitHub and let us know if you have any feedback. If you have any cool ideas, feel free to submit a pull request as well!
Are you struggling with building and managing your infrastructure? Artifakt can help you deploy your Magento 2 application on resilient and highly performant infrastructure using all the best practices we discussed above. Sounds interesting? Schedule a demo today or contact us!