Chat on WhatsApp
Performance 11 min read

Magento 2 Reindex & Index Management: The Complete Guide

Everything that actually matters about Magento 2 indexing: the two modes, how Update by Schedule works under the hood, the CLI you need, and how to clear a stuck "index locked" reindex.

Magento 2 Reindex & Index Management: The Complete Guide

Reindexing in Magento 2 is how the store turns slow, normalized EAV data into fast, flat lookup tables that the storefront reads on every request. Prices, category contents, search results, and stock all come from indexes — not live joins.

Get index management wrong and the symptoms are maddening: a product you can see in admin is missing on the frontend, a price change never appears, or a full reindex jams with “index locked.” This guide covers the whole model on Magento 2.4.4 — 2.4.9, and the fixes for the problems everyone hits.

9Indexers Magento ships with
2Index modes (Save vs Schedule)
1Minute: default cron cadence
4GBMemory to bump for a stuck full reindex

What the indexers do

Magento stores catalog data in the EAV model — flexible, but slow to read because a single product spans many tables. Indexers run those joins once and write the result into flat tables the storefront queries directly. Magento Open Source ships nine:

  • design_config_grid — design config admin grid
  • customer_grid — customer admin grid
  • catalog_category_product / catalog_product_category — which products are in which category
  • catalogrule_rule / catalogrule_product — catalog price rules
  • catalog_product_price — final prices (the heavy one)
  • cataloginventory_stock — stock status
  • catalogsearch_fulltext — the OpenSearch/Elasticsearch search index

When the underlying data changes, the matching index goes stale and must be rebuilt. How it rebuilds is the index mode.

Update on Save vs Update by Schedule

This is the single most important setting, and 2.4.8 changed its default.

ModeHow it reindexesTrade-off
Update on SaveReindexes the affected rows immediately when you save in admin or via API.Changes appear instantly, but every save is slower and admin saves can stall during bulk imports.
Update by ScheduleRecords the change in a *_cl changelog table; cron reindexes only the changed rows in batches.Saves are fast and server load is smooth, but changes appear only after cron runs (a 1–2 minute lag). Requires working cron.
Key takeaway

Use Update by Schedule on production — it is why a busy store stays responsive during imports and price changes. As of Magento 2.4.8 it is the default for every indexer, including customer_grid, which previously only supported Update on Save.

How Update by Schedule works under the hood

This is the MView (materialized view) mechanism, and understanding it makes every “why didn't my change show up” mystery obvious.

  1. You save a product. A database trigger writes the product id into a changelog table named after the index, suffixed _cl — for example catalog_product_price_cl.
  2. The indexer_update_all_views cron job compares the latest version_id in the _cl table against the value stored in mview_state.
  3. If they differ, it reindexes only the changed ids and advances mview_state. The indexer_reindex_all_invalid cron handles indexers explicitly marked invalid.

Two consequences fall out of this: if cron is not running, scheduled indexes never update (see why Magento cron stops firing), and if a changelog table grows huge, reindexing slows down — usually a sign cron has been down for a while.

The CLI you actually need

Check what mode each indexer is in and whether anything is stale:

bin/magento indexer:status
bin/magento indexer:show-mode

Switch modes (do this with the site in maintenance mode and cron paused to avoid deadlocks):

# everything to scheduled (recommended for production)
bin/magento indexer:set-mode schedule

# a single indexer back to realtime
bin/magento indexer:set-mode realtime catalog_product_price

Reindex on demand — all indexers, or just one:

bin/magento indexer:reindex
bin/magento indexer:reindex catalog_product_price cataloginventory_stock
Key takeaway

Before indexer:set-mode schedule on a live store, enable maintenance mode and stop cron. Flipping modes while cron and traffic are writing to the same tables is a classic cause of database deadlocks.

Fixing “Index locked by another reindex process”

This is the most-searched Magento indexing error. It means a previous reindex started, grabbed a lock, and died before releasing it — killed by a timeout, an out-of-memory error, or a deploy. The lock and the indexer's working status never got cleared, so every new reindex refuses to start.

The reliable fix

# 1) reset the stuck indexer state
bin/magento indexer:reset

# 2) clear stale lock files
rm -rf var/locks/*

# 3) reindex, with extra memory if it died on memory before
php -d memory_limit=4G bin/magento indexer:reindex

If a single indexer is stuck rather than all of them, reset just that one: bin/magento indexer:reset catalog_product_price. After the reset its status flips to invalid, which is expected — the next reindex rebuilds it cleanly. I hit exactly this recently on a category indexer after a killed process; reset plus a clean reindex cleared it in seconds.

Key takeaway

“Index locked” is a stuck-state problem, not a data problem. indexer:reset + clear var/locks/ + reindex fixes the overwhelming majority of cases. If it recurs, the underlying reindex is dying — check memory limits and the exception log.

Writing a custom indexer

When a module needs its own flat data, you register an indexer in indexer.xml and its MView changelog in mview.xml. The action class implements IndexerActionInterface and MviewActionInterface:

<?php
declare(strict_types=1);

namespace Panth\Catalog\Model\Indexer;

use Magento\Framework\Indexer\ActionInterface;
use Magento\Framework\Mview\ActionInterface as MviewActionInterface;

class StockScore implements ActionInterface, MviewActionInterface
{
    public function executeFull(): void
    {
        // rebuild the entire panth_stock_score index table
    }

    public function executeList(array $ids): void
    {
        // reindex only these entity ids (called by Update on Save)
    }

    public function executeRow($id): void
    {
        $this->executeList([(int) $id]);
    }

    public function execute($ids): void
    {
        // called by the MView cron with the changed ids from the _cl table
        $this->executeList(array_map('intval', (array) $ids));
    }
}

The mview.xml subscription tells Magento which table to watch (it creates the _cl changelog and triggers automatically), so your custom index participates in Update by Schedule exactly like the core ones.

Frequently asked questions

How do I reindex everything in Magento 2?

Run bin/magento indexer:reindex from the Magento root. To rebuild a specific indexer, append its name, e.g. bin/magento indexer:reindex catalog_product_price. Check bin/magento indexer:status first to see which indexers are actually stale before rebuilding all of them.

What is the difference between Update on Save and Update by Schedule?

Update on Save reindexes affected rows immediately when you save, so changes appear instantly but each save is heavier. Update by Schedule records the change in a *_cl changelog table and lets cron reindex it in batches — lighter and smoother for production, with a 1–2 minute lag. Magento 2.4.8 made Update by Schedule the default for all indexers.

Why is my price or product change not showing on the frontend?

If the indexer is in Update by Schedule mode, the change only appears after cron runs the indexer_update_all_views job — so the usual cause is cron not running. Confirm cron is firing, check indexer:status for stale/invalid indexers, and as a one-off run bin/magento indexer:reindex to force it.

How do I fix "Index locked by another reindex process"?

A prior reindex died holding the lock. Run bin/magento indexer:reset (or reset the single stuck indexer), delete stale locks with rm -rf var/locks/*, then reindex — bump memory with php -d memory_limit=4G bin/magento indexer:reindex if it died on memory before.

Should I run reindex from cron or manually?

On production, set all indexers to Update by Schedule and let cron handle reindexing automatically — never schedule a blanket indexer:reindex in crontab, which rebuilds everything and fights the MView cron. Manual reindex is for one-off fixes, deployments, or recovering a stuck indexer.

Indexers stuck, slow, or silently stale? I tune Magento indexing, MView, and cron so your catalog stays correct and fast — fixed-fee from $499 audit · $2,499 sprint · ~Nh @ $25/hr. See performance optimization.

Get your indexing sorted