order, invalidation chains and circular references under control
Once a custom indexer builds on the results of another, clean indexer dependency management decides whether the data ends up consistent or whether a downstream indexer regularly computes on stale intermediate results without anyone noticing the mistake right away.
Table of Contents
- 1. Why indexer dependency management gets overlooked
- 2. The basic principle: dependencies in indexer.xml
- 3. How invalidation travels through the dependency chain
- 4. Execution order during bin/magento indexer:reindex
- 5. Detecting and avoiding circular references
- 6. Custom dependency chains across modules
- 7. How dependencies interact with Mview
- 8. Debugging: status, order and troubleshooting
- 9. Dependency strategies compared
- 10. Summary
- 11. FAQ
1. Why indexer dependency management gets overlooked
As long as a shop only uses Magento's built in indexers, indexer dependency management barely stands out, because Magento already predefines the correct order between its core indexers. But once a custom indexer is added that builds on computed values from another indexer, for example a report based on an already aggregated price index, the execution order suddenly becomes business critical.
Without explicit indexer dependency management, such a report indexer might run before the price indexer, reading stale or not yet updated intermediate results and producing wrong numbers that only get corrected on the next run. This mistake is especially tricky because it does not surface immediately as an error, but as slightly wrong data that often only gets noticed on a spot check.
Good indexer dependency management therefore means declaring dependencies explicitly instead of relying on random execution order or timing coincidences in cron. Magento provides a built in mechanism for this, described in detail in the following sections.
2. The basic principle: dependencies in indexer.xml
The central building block for indexer dependency management is the <dependencies> node inside the indexer declaration in etc/indexer.xml. There, an <indexer id="..."> element references the indexer code the current indexer depends on. Magento internally ensures that during a full reindex run over all indexers, for example via bin/magento indexer:reindex without a parameter, the referenced indexers run first.
<?xml version="1.0"?>
<!-- app/code/Vendor/Reporting/etc/indexer.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
<indexer id="vendor_margin_report"
view_id="vendor_margin_report"
class="Vendor\Reporting\Model\Indexer\MarginReportIndexer">
<title translate="true">Margin Report</title>
<description translate="true">Aggregates margin data based on the current price index</description>
<!-- Must always run after catalog_product_price has finished -->
<dependencies>
<indexer id="catalog_product_price"/>
<indexer id="catalog_product_category"/>
</dependencies>
</indexer>
</config>
What matters for correct indexer dependency management is understanding that this mechanism only controls order during a combined reindex run across multiple indexers. If the dependent indexer is called in isolation via bin/magento indexer:reindex vendor_margin_report, Magento does not automatically check whether the dependency is up to date, it only honors the declared order during combined runs.
3. How invalidation travels through the dependency chain
Beyond pure execution order, indexer dependency management also affects invalidation. When a core indexer like catalog_product_price is marked invalid because underlying price data changed, ideally every dependent indexer should also be marked invalid, so it gets recomputed on the next reindex run too. Magento's built in dependency mechanism, however, does not automatically trigger this cascade; it only controls order, not invalidation propagation.
For true invalidation chains, the dependent indexer must either listen to the source tables of the upstream indexer via Mview itself, or a custom observer must explicitly invalidate the downstream indexer once the upstream indexer finishes. Without this extra step, a report indexer can remain unchanged for days after a price change, even though its data source was updated long ago. Clean indexer dependency management therefore always covers both layers: execution order and invalidation propagation.
<?php
declare(strict_types=1);
namespace Vendor\Reporting\Observer;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Indexer\IndexerRegistry;
/**
* Explicitly invalidates the dependent margin report indexer whenever
* the upstream price indexer finishes a reindex cycle.
*/
class InvalidateMarginReportOnPriceReindex implements ObserverInterface
{
private const DEPENDENT_INDEXER_ID = 'vendor_margin_report';
/**
* @param IndexerRegistry $indexerRegistry Resolves indexer instances by code.
*/
public function __construct(
private readonly IndexerRegistry $indexerRegistry
) {
}
/**
* Marks the dependent indexer invalid once the upstream indexer completes.
*
* @param EventObserver $observer
* @return void
*/
public function execute(EventObserver $observer): void
{
$indexer = $this->indexerRegistry->get(self::DEPENDENT_INDEXER_ID);
$indexer->invalidate();
}
}
4. Execution order during bin/magento indexer:reindex
When bin/magento indexer:reindex is run without specifying a particular indexer code, Magento internally sorts all registered indexers using a topological sort based on their declared dependencies. An indexer with a dependencies declaration is guaranteed to be processed only after all referenced indexers. This sorting is a central part of indexer dependency management and works transitively: if A depends on B and B depends on C, C runs before B runs before A.
It is important to know that this order only applies to the combined, full run. During incremental reindex via cron, every indexer runs independently according to its own Mview cycle, without Magento automatically waiting for a dependent indexer to finish. For time critical dependencies in production cron environments, the plain dependencies declaration is therefore often not enough and needs to be complemented by the explicit invalidation shown in the previous section.
5. Detecting and avoiding circular references
A common mistake in complex indexer dependency management is a circular reference: indexer A depends on B, and B in turn depends directly or indirectly on A. Magento detects such cycles while building the sort order and throws an exception instead of running into an infinite loop. The error message usually names the indexer codes involved, but is not always immediately clear for deeply nested chains spanning multiple modules.
To avoid circular references from the outset, it helps to think of dependencies strictly as a directed acyclic graph and to check, on every new dependencies declaration, whether the referenced indexer does not already transitively depend on the current indexer. In large systems with many custom indexers, a short documentation of the dependency structure pays off, so new developers do not accidentally introduce a cycle because existing dependencies are not visible at a glance.
6. Custom dependency chains across modules
In modular Magento projects with several custom modules, indexer dependency management often spans module boundaries. A module for price calculation, another for reporting, and a third for export functionality can each bring their own indexers that build on one another. Magento's module sequencing in module.xml only controls the load order of the declarations themselves, not the runtime execution order of indexers; these two concepts should not be confused.
For stable indexer dependency management across multiple modules, it is recommended to keep dependencies as flat as possible and avoid deep chains of more than three levels. Every additional level increases the risk that a single failed indexer at the start of the chain leaves all subsequent reports stale without it being noticed right away, since only the first indexer gets marked as failed.
7. How dependencies interact with Mview
An often underestimated aspect of indexer dependency management is its interaction with Mview during incremental reindex. If a dependent indexer only listens to the raw data of a core indexer, not to its computed intermediate results, it can be triggered in time but still work with stale values from the upstream indexer if that indexer has not finished yet. The solution is to either subscribe the dependent indexer to the upstream indexer's target table, if Mview technically supports that, or rely on explicit invalidation after completion.
In practice, a combination of both approaches works well: the dependent indexer reacts to raw data changes via Mview for fast response times, but is also explicitly invalidated via observer once the upstream indexer has finished its run. This ensures that no inconsistent intermediate state persists permanently, even with asynchronous processing times.
8. Debugging: status, order and troubleshooting
For troubleshooting indexer dependency management, bin/magento indexer:info is the first step to see all registered indexers and their description. bin/magento indexer:status shows which indexers are currently marked invalid. For the actual execution order during a full run, a look at the generated order Magento logs on startup of indexer:reindex helps, provided the log level is configured accordingly.
# List all indexers with their current status
bin/magento indexer:info
# Show status per indexer: valid, invalid, or working
bin/magento indexer:status
# Full reindex over all indexers respecting declared dependencies
bin/magento indexer:reindex
# Reindex a single dependent indexer (does not check upstream freshness)
bin/magento indexer:reindex vendor_margin_report
# Inspect indexer state table directly to spot stuck or invalid indexers
bin/mysql -e "SELECT indexer_id, status, updated FROM indexer_state;"
If a dependent indexer stays invalid despite a correctly updated upstream indexer, a missing observer or an incomplete Mview subscription is usually the cause. Directly comparing the updated_at timestamps in both target tables quickly reveals whether the downstream indexer has actually rerun since the last change of the upstream indexer.
9. Dependency strategies compared
Several techniques are available for indexer dependency management, differing in reliability and implementation effort.
| Technique | Controls order | Controls invalidation | Effort |
|---|---|---|---|
dependencies in indexer.xml |
Yes | No | Low |
| Explicit observer invalidation | No | Yes | Medium |
| Mview on target table | No | Yes | Medium to high |
| Combination of all three | Yes | Yes | High, but robust |
In practice, combining all three techniques is the only strategy that works reliably both for full reindex and for incremental cron operation. Anyone relying only on dependencies in indexer.xml gets a correct order during manual runs but no automatic invalidation propagation during ongoing operation. Consistent indexer dependency management means deliberately closing that gap instead of treating it as an edge case.
Mironsoft
Magento 2 indexer architecture and data consistency
Are your reports relying on stale indexer data?
We analyze existing indexer dependencies, close invalidation gaps between indexers that build on each other, and make sure your data stays consistent even across complex chains.
Dependency audit
Documenting existing indexer chains and uncovering circular references
Invalidation retrofit
Adding explicit observers and Mview subscriptions for real consistency
Monitoring
Establishing lasting visibility into indexer status and freshness
10. Summary
Solid indexer dependency management in Magento 2 consists of two separate but related layers: declarative order via dependencies in indexer.xml, which only applies during combined reindex runs, and active invalidation propagation via observers or Mview, which ensures dependent indexers are actually recomputed during ongoing operation whenever their data source changes.
Anyone relying only on declarative order risks silent data inconsistencies during production cron operation. Anyone who combines both layers and keeps dependency chains flat gets indexer dependency management that remains traceable and maintainable even as module count and calculation chains grow more complex.
Indexer dependency management in Magento 2, the essentials at a glance
Order
dependencies in indexer.xml enforces execution order only during full, combined reindex runs.
Invalidation
Explicit observers or Mview subscriptions needed to automatically invalidate dependent indexers.
Circular references
Think of dependencies as a directed acyclic graph, keep chains flat, Magento throws an exception on cycles.
Debugging
indexer:info, indexer:status and comparing updated_at timestamps quickly find gaps.