Static Content Deployment: Symlink vs Copy Behavior on Read‑Only Filesystems
0 reputation · 07 Nov 2022, 05:10 UTC
0 reputation · 07 Nov 2022, 05:10 UTC
During a production deployment the setup:static-content:deploy command must place generated assets into pub/static while the application root is mounted read‑only. Magento can satisfy this requirement by creating symlinks or by copying files, but the documentation does not state which strategy is chosen or whether a configuration option forces one approach.
The deployment logs in var/log/system.log only report generic permission errors unless the command is run with -vvv, making it difficult to confirm the actual method used in automated pipelines.
Which configuration flag, if any, controls the symlink versus copy decision? Does the active deployment mode (production vs developer) influence the choice? How can the method be verified programmatically without enabling verbose logging?
33275 reputation · 07 Nov 2022, 16:27 UTC
There is no configuration flag — not in env.php, config.php, and not as an option on setup:static-content:deploy — that forces symlink versus copy. The command's options cover areas, themes, locales, languages, jobs, and -f (force), but nothing about link strategy. The decision is made implicitly by the application mode: developer mode publishes static view files as symlinks; production and default modes copy the files into pub/static.
Confirmed by behavior: switching modes changes the outcome. After bin/magento deploy:mode:set developer and a deploy, files under pub/static are symbolic links back into var/view_preprocessed and module source paths. In production mode the same paths contain real files.
Likely but not officially documented as a toggle: the internal mechanism is that developer mode uses a symlink-based materialization/publisher while production mode uses a copy-based one, chosen for performance and atomicity. Treat this as version-sensitive convention rather than a guaranteed contract — verify against your exact Magento/Adobe Commerce version before building pipeline logic around it.
Neither strategy avoids writes. Creating a symlink is still a filesystem write, so pub/static (and var) must be writable regardless of mode. The generic permission errors in var/log/system.log almost certainly mean the mount is the blocker, not the link strategy. The standard fix is to keep the application root read-only but mount pub/static and var as writable volumes, then re-run the deploy. If the permission errors disappear, the strategy question was never the issue.
-vvvInspect the result, not the logs. Two options:
# Shell: list any symlinks produced by the deploy
find pub/static -type l | head
# Confirm the active mode
bin/magento deploy:mode:showFrom PHP, for example in a pipeline health check:
$asset = BP . '/pub/static/frontend/Vendor/theme/en_US/css/styles-m.css';
$isSymlink = is_link($asset); // true => developer-style symlink deploy
$target = $isSymlink ? readlink($asset) : null;An empty find result plus real files present means copy mode; links present means symlink mode. This is deterministic and needs no log verbosity.
bin/magento deploy:mode:set production.dev/static/sign) changes asset URLs/naming for cache busting but does not change link-vs-copy.One caveat: if your deploy runs in production mode yet you still see symlinks, that would contradict the conventional behavior — share the output of deploy:mode:show and one readlink result, since that combination would point to a customization or version-specific change worth flagging for review.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.