Skip to main content

— Technical

Fetching product row_id vs entity_id in Magento 2 and Adobe Commerce

5 June 2025 · 4 min read

magento adobe-commerce database

If you’ve worked across both Magento Open Source and Adobe Commerce (Cloud), you’ve run into this: a query that works perfectly on community edition breaks on Commerce because the product’s internal identifier is different.

On Open Source, the product’s primary identifier is entity_id. On Adobe Commerce, it’s row_id — a separate column used by the staging and scheduling system to track versioned product states. Same concept, different field name, and if you hardcode either one you’re writing a module that only works on one edition.

The correct approach is to let Magento tell you which field to use at runtime.

Why the split exists

Adobe Commerce’s content staging feature allows you to schedule product changes — price updates, attribute edits, going live with a new description — all versioned and queued for future deployment. To support this, Commerce can’t use entity_id as the canonical identifier because there may be multiple versions of a product row in the database at different points in time.

row_id is the staging-aware identifier. It points to a specific version of a product record. entity_id identifies the product itself across all its versions.

On Open Source, there’s no staging, so entity_id and row_id are the same value and only one column exists.

The wrong way

$rowId = $product->getData('row_id'); // Only works on Commerce
$entityId = $product->getId();        // Works on both, but not always what you need

Hardcoding row_id silently fails on Open Source — getData('row_id') returns null because the column doesn’t exist. Hardcoding entity_id means your staging-aware logic on Commerce will operate on the wrong version of the product.

The correct way

Magento’s MetadataPool service knows which field is the link field for any given entity type. Ask it.

<?php
declare(strict_types=1);

namespace YourVendor\YourModule\Model;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Framework\EntityManager\MetadataPool;

class GetProductLinkFieldValue
{
    public function __construct(
        private readonly MetadataPool $metadataPool
    ) {}

    public function execute(Product $product): int
    {
        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
        $linkField = $metadata->getLinkField();

        // Returns row_id on Adobe Commerce, entity_id on Open Source
        return (int) $product->getData($linkField);
    }
}

$metadata->getLinkField() returns the string 'row_id' on Commerce and 'entity_id' on Open Source. The product model always loads both columns, so getData() works in either case.

When you actually need this

The scenarios where this matters are narrower than you’d think, but they’re important:

Custom EAV attribute joins. If you’re joining to an EAV value table (catalog_product_entity_varchar, etc.) you must join on the link field, not entity_id, or you’ll get wrong values when staging is active.

Direct database writes. Any module inserting or updating product attribute values directly via SQL needs to write to row_id (Commerce) or entity_id (Open Source). Using the wrong field means your write targets a row that staging may never publish.

Reindex triggers. Some custom indexers need to reference the staging-correct row. Using entity_id here can cause indexing to operate on the published version instead of the staged one.

Getting the identity field too

MetadataPool also exposes getIdentifierField(), which always returns entity_id — the product’s permanent identifier regardless of staging. Use this when you need to reference the product itself rather than a specific version of it.

$identityField = $metadata->getIdentifierField(); // Always 'entity_id'
$linkField     = $metadata->getLinkField();        // 'row_id' or 'entity_id'

The rule of thumb: use getLinkField() when writing EAV data, use getIdentifierField() when referencing the product for non-versioned data (like URL keys, category assignments, and website relations — these use entity_id even on Commerce).

Once you internalise this split, the pattern clicks. The staging system is complex, but the interface Magento exposes to work with it correctly is straightforward.

Savan Padaliya

Savan Padaliya

Senior Engineering Consultant

← Back to writing