Magento’s database is normalised for writing, not reading. A product’s price, stock, category membership and attribute values live in dozens of tables - far too many to join on every storefront request. Indexers solve this by denormalising that data into flat, read-optimised tables. Understanding how they work explains half of all “my change didn’t show up on the site” mysteries.
The Two Modes
Every indexer runs in one of two modes:
- Update on Save: the index is updated immediately when an entity changes in the admin. Simple, but a big import means every row triggers index work synchronously - painful on large catalogs.
- Update by Schedule: changes are logged and processed by cron. This is the only sensible mode for production stores with regular imports.
You set the mode per indexer:
bin/magento indexer:set-mode schedule catalog_product_price
bin/magento indexer:set-mode schedule catalogsearch_fulltext
How Update by Schedule Works
The mechanism is called mview (materialised view). Each indexer with schedule mode has a corresponding *_cl changelog table - for example catalog_product_price_cl. MySQL triggers on the main tables write changed entity IDs into the changelog. When cron runs the indexer, it reads pending IDs from the changelog, reindexes just those entities, and marks them processed via the mview_state table.
This is why partial reindexing is fast: a price change to 50 products touches 50 IDs, not the whole catalog.
The Indexers That Matter
catalog_product_price- price calculations including tier and special prices; stale prices are a legal and commercial problem, so watch this one closelycataloginventory_stock(and MSI’sinventory_stock_*views) - salability on the storefrontcatalog_product_attribute- layered navigation and attribute-based filteringcatalogsearch_fulltext- search resultscatalog_category_productandcatalog_product_category- which products appear in which categories
Common Failure Modes
- Cron not running: changelog tables grow unboundedly and the storefront slowly goes stale. Check
SELECT COUNT(*) FROM catalog_product_price_cl;- a number in the millions is a smoking gun. - Mode accidentally on save during an import: imports crawl. Set schedule mode first.
- Index invalidated by a buggy module: custom code writing products without triggering mview leaves indexes wrong with no visible error.
Operational Habits
- Always schedule mode in production
- After bulk imports, run
bin/magento indexer:reindexfor the affected indexers rather than waiting for cron to chew through a huge backlog - Monitor
mview_state- theversion_idgap between changelog and state tells you the backlog size - Never
TRUNCATEa*_cltable to “fix” a backlog; reindex fully instead, or you silently lose changes
Indexers are the reason Magento can serve a complex catalog quickly. Treat them as critical infrastructure - schedule mode, monitored cron, watched backlogs - and they will quietly do their job for years.