Skip to content
How-to guide

Operate Magento

synsmarts builds Magento from your Composer project and deploys the resulting immutable application image. MySQL, Redis, OpenSearch, Nginx, PHP, scheduled jobs, and optional Varnish are managed services around that image.

A Magento deploy must contain:

  • composer.json at the selected source root;
  • bin/magento;
  • application modules, themes, patches, and configuration required by the release.

Include composer.lock for a reproducible dependency set and commit it when using Git. A build can proceed without it, but dependency resolution can change between otherwise identical deploys.

A Workspace transfer may include the production vendor/ tree. synsmarts reuses it only when it passes four checks:

  • Composer’s installed metadata exactly matches every production package in composer.lock;
  • the autoloader and package install paths exist inside the source;
  • Composer validates manifest/lock consistency;
  • the selected PHP runtime satisfies the installed requirements.

Symlinked metadata, or an incomplete or mismatched vendor tree, is discarded and rebuilt with Composer. When the tree passes validation, synsmarts includes vendor/ in the image build even if the source .dockerignore excludes it. Use .deployignore to omit vendor/ from the Workspace snapshot when you want Composer to rebuild dependencies instead.

When the selected source doesn’t contain a validated complete vendor/, store your Adobe Commerce Marketplace credentials as the COMPOSER_AUTH build secret under Vars and secrets. Its value is the complete Composer authentication JSON, including the repo.magento.com http-basic public and private keys. A validated complete vendor build doesn’t read or mount Composer credentials.

The platform-managed Magento build performs the production preparation steps, including:

  • exact production lock/package/install-path validation and composer check-platform-reqs --no-dev when a complete vendor/ is supplied, or authenticated composer install --no-dev when dependencies must be rebuilt;
  • module enablement when app/etc/config.php is absent, with admin two-factor authentication and sample-data modules disabled. A committed config.php is kept as your module list, including its two-factor setting, and the build fails if it omits a module that exists in your code (MAGENTO_CONFIG_PHP_MODULES_MISSING names the modules). If your committed file enables two-factor authentication while your store currently runs with it disabled, the first deploy after this change re-enables it; make sure an admin has an authenticator configured before you deploy;
  • optimized Composer autoload generation;
  • dependency-injection compilation;
  • static-content deployment for every theme, in en_US plus each locale set at the default, website, or store view scope and each admin user’s interface locale. The deploy reads those locales from your database before the build and adds the locales committed in app/etc/config.php. If the database can’t be read, the build deploys en_US and the config.php locales only.

Don’t add a second production compilation sequence after deployment. Changes to Composer dependencies, generated code, or static assets belong in the next selected source and build.

Apart from merged CSS and JavaScript, which Magento writes to pub/static/_cache on request, the storefront serves only the static files your last build produced. A locale you set on a store view or admin user after that deploy has no stylesheets or scripts until the next deploy, so pages in that locale render unstyled. Deploy after changing a locale. The CSS and JavaScript minification settings under Stores > Configuration > Advanced > Developer behave the same way: set in the admin, they make pages link .min files the build didn’t produce. Commit them to app/etc/config.php with bin/magento config:set --lock-config so the build produces those files.

The web server runs your release on a read-only filesystem. At request time it can write to your shared paths, to the rest of var/, and to /tmp. Outside the shared paths, var/ and /tmp start empty on each pod and aren’t shared between pods. A module that writes anywhere else while serving a request fails with Read-only file system; point it at var/ or make its directory a shared path.

Each release explicitly uses Git or Workspace:

  • Choose Git when the intended Magento project is a branch, tag, or commit in the connected repository.
  • Choose Workspace when the intended project is the current server-side file tree prepared through SSH or another deployment tool.

When a repository is connected, both sources remain available. A Workspace deploy doesn’t commit its files to Git. A later successful Git deploy refreshes non-preserved Workspace code from the built release on a best-effort, non-gating basis and can remove changes that exist only in Workspace. A refresh failure leaves the Git release live and can leave older Workspace code. Make the equivalent repository change when it must survive future Git releases.

Use an exact Git commit SHA when you need a reproducible Git release.

  1. Update the source intended for the release and composer.lock.
  2. Confirm either the source contains the complete production vendor/ tree or COMPOSER_AUTH is configured and current.
  3. Run Magento tests, static analysis, and dependency checks.
  4. Deploy the selected Git revision or prepared Workspace.
  5. Follow build, migration classification, migration, rollout, and verification in the deploy detail.
  6. Test storefront, admin, checkout, customer login, search, media, cache, and scheduled work.

The deploy first decides whether the selected source changed a migration-bearing path.

  • A Git deploy compares the currently serving commit with the resolved candidate commit.
  • A Workspace deploy compares its Workspace schema fingerprint with the serving Git commit when that baseline is available.
  • A Workspace snapshot containing .deployignore can’t produce a trustworthy schema fingerprint because ignored paths could hide migration files. It is treated as unknown rather than code-only.

Migration-bearing paths include composer.json, composer.lock, db_schema.xml, db_schema_whitelist.json, module.xml, app/etc/, Setup/, Patch/, theme.xml, a theme’s registration.php, queue*.xml, communication.xml, indexer.xml, and mview.xml. A change limited to theme files or those four declarations takes the additive path with no schema change to apply.

When a migration-bearing path changed, synsmarts builds the new image and compares its post-build schema inventory with the serving image. The inventory records the schema declaration Magento resolves from the enabled modules at build, so the comparison includes Composer-installed modules under vendor/.

Changes limited to added tables, a nullable or defaulted column, non-unique indexes, or a varchar widened without crossing 255 bytes in the table’s character set can be additive. Any column data-type change, such as int to bigint or a varchar growing past 255 bytes, uses breaking treatment, as do drops, renames, other existing-column changes, constraint changes, whitelist-only changes, or changed Setup or Patch PHP. Additive DDL on an existing table estimated above 1,000,000 rows also uses maintenance. Any unavailable or ambiguous static evidence becomes a breaking or unknown candidate. The status probe then decides whether that candidate needs a maintenance window.

For example, this declaration can be additive when the target table is below the live-DDL threshold and the rest of the inventory remains compatible:

app/code/Acme/Module/etc/db_schema.xml
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<table name="acme_order">
<column xsi:type="varchar" name="external_reference"
nullable="true" length="64" comment="External reference"/>
</table>
</schema>

Every Magento deploy, code-only included, runs a release Job on the new image before traffic moves. The Job refuses a database whose schema is newer than the release’s code. It imports the release’s committed configuration with bin/magento app:config:import, runs setup:upgrade when the deploy path requires it, and registers themes. It then requests each store’s home page, one product page, and one category page from the new release; an error status or Magento’s error page fails the deploy, and the previous release keeps serving.

A code-only deploy takes no backup and no maintenance window. It uses the maintenance-window path instead when the database still has pending changes from an earlier failed release, or when the committed config.php would delete or rename an existing store or website.

Additive, breaking, and unknown deploys take a pre-migration backup before the migration Job runs. Additive deploys take it first, then pause scheduled work and run the managed migration Job while the previous release keeps serving.

Breaking and unknown candidates first run a separate status probe from the new image. The probe runs before customer notification, the maintenance page, scheduled-work pause, or the real migration Job. A clean schema promotes with no maintenance window or notification. When migration is required or the probe is unavailable, synsmarts pauses scheduled work, including queue consumers, sends the notification, enters maintenance, waits until visitors receive the maintenance page, takes the pre-migration backup, and runs the managed migration Job:

Check Magento database status
bin/magento setup:db:status

If the database isn’t current, the Job runs bin/magento setup:upgrade --keep-generated from the new image and verifies database status again.

The Job reads app/etc/config.php from the release image, so modules and themes added in this release are installed and registered by this deploy. A deploy that adds only a theme also runs the Job and registers the theme. Before its first database change the Job writes and deletes one test object in media storage; if that fails, the deploy stops before any database change. The Job needs the store’s cloud identity; a store whose identity is missing fails the deploy before any change, and support restores it.

  • Additive: the old release keeps serving with no planned interruption. If the migration fails, synsmarts doesn’t restore the backup because that would discard live writes. Schema changes and data patches that completed stay applied and are listed in deploy details; deploy the same source again to finish, and don’t expect a rollback of that deploy. When the deploy details say the applied changes are unknown, contact support before deploying again. Before changing anything, the Job asks Magento what setup:upgrade would change in the live database. If that includes anything beyond the additive changes above, such as dropping the tables of a module you disabled or a column another module marks disabled="true", the deploy uses the maintenance-window path instead. If the database still has pending changes from an earlier failed release, the deploy uses the maintenance-window path too, with a fresh backup taken once the maintenance page is up. When the only failure is a brief lock wait on Magento’s indexer triggers, the Job runs setup:upgrade once more; a second wait moves the deploy to the maintenance-window path.
  • Breaking or unknown: a clean status probe promotes without a maintenance window, notification, or real migration Job. A migration-required result or unavailable probe falls through to the notified maintenance window. If that migration fails before promotion, synsmarts keeps a copy of the failed database, restores the pre-migration backup, and returns the previous release to service. The backup was taken after the maintenance page went up, so no order or update the store accepted is lost.
  • Restore failed: maintenance stays on and support intervention is required.

Before promotion, the new release’s home page and one product page must each end at HTTP 200 within 45 seconds through the preview route. The check follows up to five redirects to your app’s own domains, so a home page that redirects to your www base URL passes. Any other status, such as a 401, or a redirect to another host fails the check, stops the deploy, and the previous release keeps serving.

See How deploys move from code to traffic for the complete classifier and rollback model.

The managed SSH shell can run Magento commands from the application directory. Start with read-only checks:

Inspect Magento from the managed shell
bin/magento --version
bin/magento setup:db:status
bin/magento indexer:status
bin/magento cache:status

The shell reads app/etc from the Workspace. After each successful deploy, from Git or the Workspace, synsmarts copies the built release’s app/etc into the Workspace, except env.php, so these commands reach the same database version check as the store. The copy finishes a few minutes after the deploy completes; until then the shell can show the previous release’s app/etc.

The managed shell also includes n98-magerun2. Inspect the installation with n98-magerun2 sys:info. For a database console, run site-mysql; it supplies the App’s connection through a private temporary defaults file and removes that file when the client exits.

The bundled magerun refuses db:console (including mysql-client), db:dump, db:import, db:info, and db:query, including abbreviated names. Those upstream commands put the database password in process arguments, where a process listing can expose it. Use site-mysql -e 'SELECT 1' for a query; contact support for database dump or import assistance.

Use mutating commands only when the action is intended to affect runtime state, not to replace the selected release source or managed migration. In particular:

  • change modules, themes, Composer packages, and DI inputs in the source intended for the next release;
  • let the deploy build compile generated code and static content;
  • let the deploy workflow apply database schema and data patches;
  • use the portal’s Varnish purge action for full-page cache invalidation.

Magento depends on scheduled execution for indexing, email, catalog rules, consumers, and other application work. New Magento Apps include a Scheduled Job named magento-cron. It runs magento-cron-runner every minute with Forbid concurrency.

The seeded job is an ordinary customer-owned Scheduled Job. It is visible, editable, pausable, and deletable; counts toward the 50-job limit; and isn’t recreated after deletion. Keep it unless another scheduler fully replaces the same Magento work.

While magento-cron is active and runs every minute, synsmarts raises an alert in Diagnostics when it records no run for more than five minutes; a skipped run doesn’t count as a run. The check stops while the job is paused, deleted, or on another schedule, and while scheduled work is suspended, such as during a deploy, a database or cache change, or an App suspension. A missing run record doesn’t by itself prove that Magento’s cron stopped, so check the job’s history and the scheduler’s status.

A second alert appears in Diagnostics when magento-cron hasn’t completed a run successfully for more than 10 minutes. On a migrated store, the alert watches the one job whose command runs bin/magento cron:run, whatever its name; keep exactly one such job. It keeps watching while the job is paused or deleted, while every run fails, and while one run is still holding the job. Only an App suspension stops it.

Magento runs some cron groups, such as index, consumers and analytics, in their own processes. synsmarts runs each of them as its own line of magento-cron and starts it every minute, as Magento does. A long reindex or a busy queue consumer then holds only its own Magento job: email, sales and the group’s other jobs keep running. Their runs appear in the job history as magento-cron.index, magento-cron.consumers and so on, each reported complete only when its group’s processes end. When a Magento index job is still running after 15 minutes, Diagnostics shows an alert: catalog, price and stock changes that job handles reach search and listings once it ends. A category move or a large import can queue every product for reindexing on a big catalog.

Magento runs each job at most once per cron:run, one scheduled minute at a time. After scheduled work pauses, for example during a deploy, every job that runs each minute would stay late by the length of the pause. synsmarts adds a magento-cron.catchup run every minute. It removes each job’s older overdue entries from Magento’s cron schedule, so the job runs once and is on time again. On a migrated store it does the same for the job that runs bin/magento cron:run.

Your own Scheduled Jobs never hold up magento-cron: the limit of two of your jobs running at once doesn’t count it or its group lines.

Magento’s queue consumers, including the one that builds an admin export (System → Data Transfer → Export), run in magento-cron.consumers. With remote storage, Magento writes the whole export file to temporary storage before uploading it; the scheduled-job runner has 4 GiB for those files, enough for a full export of about one million products.

Don’t replace magento-cron-runner with a bare bin/magento cron:run Scheduled Job: it loses that split and the completion reporting.

Keep other durable commands and schedules in Scheduled Jobs, then verify the next run and its output after a release.

Useful checks include:

Inspect scheduled Magento work
bin/magento cron:run
bin/magento indexer:status
bin/magento queue:consumers:list

Run cron:run manually only for controlled verification. Avoid defining the same recurring command in more than one scheduler.

See Manage scheduled jobs.

  • Use Magento cache commands for Magento application cache types.
  • Use Purge cache on the Varnish service card to invalidate the managed full-page cache.
  • Expect a cold cache after each deploy. After every promotion, synsmarts flushes the configuration cache, runs bin/magento cache:clean, purges Varnish when it’s enabled, and warms the storefront for up to a minute. The deploy shows Complete without waiting for that work.
  • Varnish keeps Magento’s “page not found” answer for up to 5 minutes, so a URL you create can show the 404 page for that long. Use Purge cache to serve it at once.
  • Varnish ignores common ad click ids (Google, Meta, Microsoft, TikTok, X, LinkedIn, Pinterest, Reddit, Yandex, Snapchat) and utm_* tags when it looks up a page, so a tagged ad click is served from cache. Your analytics still read them from the browser’s address.
  • Review Redis settings before changing cache eviction behavior.
  • Review OpenSearch version compatibility before selecting a different offered version.
  • After catalog or search changes, verify indexer status and a representative storefront search.

See Configure services and Service configuration fields.

  1. Confirm the target Magento release supports the offered PHP, MySQL, OpenSearch, and Composer dependency versions.
  2. Update composer.json, composer.lock, modules, themes, and patches together.
  3. Test compilation, static content, schema changes, checkout, admin, cron, indexing, and search outside production.
  4. Verify a recent database backup.
  5. Deploy one exact Git revision or reviewed Workspace snapshot and review its migration classification.
  6. Verify the customer journeys and scheduled work after promotion.

synsmarts updates the managed runtime and services. Magento core, extensions, themes, patches, and their compatibility remain your responsibility.

  • Missing composer.json or bin/magento means the source isn’t a complete Magento project.
  • Missing Marketplace credentials means dependency reconstruction was required and COMPOSER_AUTH is absent or doesn’t contain valid repo.magento.com credentials.
  • A vendored dependency validation failure means the supplied vendor/ doesn’t exactly represent the production packages in composer.lock; repair the transferred tree or configure Composer credentials so it can be rebuilt.
  • app/etc/env.php and auth.json must be removed from whichever source is selected. If either was committed to Git, also treat the repository history as exposed credential material.
  • A compile failure should be fixed in the selected Git revision or prepared Workspace, not by changing generated files after the build.
  • A schema or data-patch failure should be reviewed in deploy details before retrying.
  • A database newer than the release’s code means the selected source is older than the last migration applied; deploy a revision that includes the modules and versions the database already has.
  • A failed storefront or preview check means the new release returned an error, Magento’s error page, or a slow response for a checked page. Reproduce that page from the same source and fix it there; the previous release keeps serving meanwhile.
  • A search problem should be separated into indexer state, OpenSearch health, and storefront query behavior.

Use Recover from a failed deploy and Get support when the failing layer is managed by synsmarts.