Adobe Commerce Developer Expert cheat sheet
Adobe Commerce Developer Expert · Keep the key ideas within reach.
Adobe Commerce Architecture and Customization
Request flow: index.php → Bootstrap → app object → FrontController → router match → action; area (frontend/adminhtml/webapi/crontab) determines DI config and layout handles.
Module registration requires app/code///registration.php plus etc/module.xml; module order in module.xml controls load order of config merges.
Config merge precedence (low to high): app/etc/.xml, module etc/.xml, area-specific etc//*.xml, then etc/di.xml in each layer; later modules override earlier ones.
Areas are declared in etc/di.xml or by directory presence; only modules with etc//di.xml or routes participate in that area's config scope.
Layout XML merges by handle name; / modify existing nodes, and operate after merge, and layout updates are cached per handle.
Plugins (interceptors) run around public methods only; private, final, and static methods cannot be intercepted, and constructors are never intercepted.
Customization preference order: plugin > preference > event/observer > around-hack; preference replaces the class globally and is resolved at DI compile time.
Themes inherit via theme.xml ; static files resolve through pub/static with fallback chain module → parent theme → current theme.
Commerce Development: PHP, Modules, DI, Plugins
di.xml argument types: ; object arguments are instantiated by the ObjectManager at compile time.
Virtual types (xsi:type="virtualType") define named configured instances of a class; they do not create new PHP classes and are preferred over subclasses for argument overrides.
Plugin order: sortOrder attribute on (lower runs first); same-name plugins in different modules resolve by module sequence.
Around plugin signature: public function aroundX(Subject $subject, callable $proceed, ...$args); $proceed invokes next plugin or original; forgetting to return $proceed() breaks the chain.
Before plugins can modify arguments only by returning an array of arguments; after plugins receive $result and may return a modified value.
ObjectManager::getInstance() is discouraged; inject dependencies via constructor. Factories (\Factory) and proxies (\Proxy) are generated for non-injectable or heavy classes.
Interceptor generation writes to generated/code; changes to di.xml require bin/magento setup:di:compile in production mode (developer mode regenerates on demand).
Proxies delay instantiation until a method is called; use them for cyclic dependencies or expensive classes injected but rarely used.
CLI commands extend Symfony Command and are registered via etc/di.xml arguments.
Database, EAV, and Data Modeling
EAV entity tables: eav_entity_type, eav_attribute, eav_entity_attribute, plus per-entity value tables catalog_product_entity_ (int, varchar, text, decimal, datetime).
Flat vs EAV: catalog_product_flat_ and catalog_category_flat_ are built by indexers; enabling flat removes joins but adds index rebuild cost.
Static attributes live in the main entity table (catalog_product_entity); EAV attributes are joined via attribute_id and store_id (0 = default/admin scope).
Store-scoped values: rows with store_id = 0 are defaults; a store-specific row overrides; absence of a store row falls back to 0.
declarative schema (etc/db_schema.xml) is the source of truth; bin/magento setup:db-declaration:generate-whitelist and setup:upgrade reconcile; never edit core schema directly.
Data patches (Magento\Framework\Setup\Patch\DataPatchInterface) run once and are recorded in patch_list; schema patches in patch_list with patch_type = schema.
Collections use Magento\Framework\Model\ResourceModel\Collection\AbstractDb; addAttributeToSelect/addAttributeToFilter build EAV joins; getSelect() exposes the Zend/Laminas query.
Foreign keys and indexes are declared in db_schema.xml and ; unique constraints enforce single-row-per-scope semantics.
Performance, Caching, and Deployment/Configuration
Cache types: config, layout, block_html, collections, reflection, db_ddl, compiled_config, eav, customer, customer_notification, full_page, translate, config_integration, target_rule, graphql_query_resolver.
FPC (full_page cache) stores rendered HTML keyed by URL + customer group + store; cacheable="false" in layout removes a block from FPC via X-Magento-Tags.
Cache tags: each cached item carries tags (e.g., cat_p_, cms_b_); bin/magento cache:clean invalidates by type, cache:flush clears the storage backend.
Production deploy sequence: setup:di:compile → setup:static-content:deploy -f → setup:upgrade → cache:flush; developer mode skips compilation and static deploy.
Modes: default, developer (no compile, verbose errors), production (compiled, no on-demand generation). Set with bin/magento deploy:mode:set.
Indexers run in Update by Schedule (cron) or Update on Save; bin/magento indexer:reindex and indexer:set-mode control behavior; invalid indexers fall back to on-the-fly.
Varnish sits in front of the app for FPC; Magento purges via X-Magento-Tags and BAN requests; configured in env.php under http_cache_hosts.
Redis handles backend cache, session storage, and FPC (page_cache) when configured in app/etc/env.php; use separate Redis databases per role.
env.php holds deployment-specific config (DB, cache, crypt key, mode); config.php holds module enable/disable state; app/etc/config.php is committed, env.php is not.