Static Content Deployment
Why browsers read pub/static, what setup:static-content:deploy does, and the symlinks developer mode uses instead.
bin/magento setup:static-content:deploy [-f] [-s quick|standard|compact] [-a frontend] [-t Vendor/theme] [-j 4] [<locale> ...]No browser reads app/design or app/code. It reads pub/static, the only directory the web server exposes. Static content deployment is the step that collects, compiles and copies view files from modules and themes into pub/static/<area>/<Vendor>/<theme>/<locale>/. Every theme and every locale gets its own tree, which is why the directory is large and why restricting the deploy to the themes and locales in use saves real time.
The command
bin/magento setup:static-content:deploy does the work. In production mode it is mandatory: nothing is generated on request, so a file you changed is invisible until the command runs. It also writes pub/static/deployed_version.txt, the value Magento puts into asset URLs so browsers stop using cached copies. The default strategy is quick; standard and compact are also available through -s, and -j runs several jobs in parallel.
Developer mode does it for you
In developer and default modes files are materialised on request, and where possible as symlinks into the source directory, so editing a source file changes what the browser receives. For that reason the command refuses to run in those modes unless you pass -f.
What trips people up
Stale files. If a change does not appear, delete the generated trees and let them rebuild: pub/static/frontend and var/view_preprocessed, then bin/magento cache:flush. Keep pub/static/.htaccess.
Example
# Run from the Magento root, as the file-system owner.
# In developer mode the command declines, by design:
bin/magento setup:static-content:deploy
# NOTE: Manual static content deployment is not required in "default" and "developer" modes.
# In "default" and "developer" modes static contents are being deployed automatically on demand.
# If you still want to deploy in these modes, use -f option: 'bin/magento setup:static-content:deploy -f'
# In production mode it is required, and -f is not needed:
bin/magento deploy:mode:set production
bin/magento setup:static-content:deploy en_US de_DE -j 4
# New content version: 1759658400
# Execute: frontend/Acme/storefront/en_US
# Execute: frontend/Acme/storefront/de_DE
# Execute: adminhtml/Magento/backend/en_US
bin/magento cache:flush
# Where the files land:
# pub/static/frontend/Acme/storefront/en_US/css/styles-m.css
# pub/static/frontend/Acme/storefront/de_DE/css/styles-m.css
# pub/static/deployed_version.txt <- 1759658400When to use it
- A CSS change works locally but not on staging after a release.
- Cut build time by deploying only the one theme and one locale the store uses.
- Recover a storefront that renders unstyled after a half-finished deploy.
- Explain to a colleague why editing a .less file on a production server changes nothing.
More examples
Clearing stale static content in developer mode
The usual fix when an asset change refuses to appear. Deleting the generated trees makes the next request rebuild them from source. Delete the contents, not the directories: pub/static/.htaccess and var/view_preprocessed are expected to exist, and removing the .htaccess file exposes the directory listing.
# Developer mode, change not showing up
rm -rf pub/static/frontend/*
rm -rf var/view_preprocessed/*
bin/magento cache:flush
# pub/static/.htaccess must survive; check it is still there
ls -la pub/static/.htaccessA narrow deploy for one theme
The default deploy builds every registered theme, including Blank, Luma and the admin theme, in every enabled locale. On a build server that is minutes you do not need. Restrict the area, the theme and the locale, and exclude what you never serve. Keep the admin area deployed, or the admin loads without styles.
# Storefront theme only, one locale, compact output
bin/magento setup:static-content:deploy -f \
--area frontend \
--theme Acme/storefront \
--strategy compact \
en_US
# The admin still needs its own area
bin/magento setup:static-content:deploy -f --area adminhtml en_USWhere it sits in a production build
The order matters. Code generation and dependency injection compilation come before static deployment, because the deploy reads generated files, and the cache flush comes last. This is the sequence a release script runs after pulling new code; running the static deploy first and compiling afterwards produces a storefront with missing assets.
composer install --no-dev
bin/magento setup:upgrade --keep-generated
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f en_US -j 4
bin/magento cache:flush
Discussion