Cartridge Overrides & superModule

Follow module.superModule through cartridge order, extend exported helpers and constructors, and navigate inherited implementations

module.superModule refers to the matching module in the next cartridge that supplies it after the current cartridge. The language server models that relationship, so the base value can carry exported members, signatures, documentation, and definition locations into your override.

Read the cartridge chain

For an active cartridge order of app_custom:app_brand:app_base, imagine all three cartridges contain cartridge/scripts/helpers/productLabels.js:

Location of the expressionResolution
require('*/cartridge/scripts/helpers/productLabels')The first matching implementation, app_custom
module.superModule inside app_customThe next matching implementation, app_brand
module.superModule inside app_brandThe next matching implementation, app_base
module.superModule inside the last matching implementationNo further parent implementation

Cartridges without that relative file are skipped. This is a relationship between matching module paths, not a general JavaScript superclass. Keep the active site scope consistent with the storefront you are developing.

Extend a helper module

This smaller example uses app_custom:app_base. Both files have exactly the same path relative to their cartridges.

app_base/cartridge/scripts/helpers/productLabels.js
/** @param {dw.catalog.Product} product */
function getLabel(product) {
    return product.name || product.ID;
}

module.exports = { getLabel: getLabel };
app_custom/cartridge/scripts/helpers/productLabels.js
var base = module.superModule;

/** @param {dw.catalog.Product} product */
function getLabel(product) {
    return base.getLabel(product) + ' · Online exclusive';
}

module.exports = { getLabel: getLabel };
cartridge/scripts/helpers/productTile.js
var ProductMgr = require('dw/catalog/ProductMgr');
var labels = require('*/cartridge/scripts/helpers/productLabels');

function getLabelForId(id) {
    var product = ProductMgr.getProduct(id);
    return product ? labels.getLabel(product) : '';
}

module.exports = { getLabelForId: getLabelForId };

Inspect the base exports

In the override, invoke completion after base.. The base module's getLabel should be offered. Hover or signature help explains its Product parameter.

Follow the inherited implementation

Use Go to Definition on base.getLabel. It should lead to app_base in this two-cartridge example. Continue through additional overrides one layer at a time.

Follow the public module

Use Go to Definition from the caller's labels.getLabel. Its target is the selected exported implementation. Use Find All References on an export to inspect indexed consumers.

Keep inherited exports and add your own

A common SFCC pattern adds properties to the imported base and re-exports it. The analyzer combines the parent module's type with recognized properties added by the override:

app_custom/cartridge/scripts/helpers/productLabels.js
var base = module.superModule;

/** @param {dw.catalog.Product} product */
base.getBadge = function (product) {
    return product.online ? 'Available online' : '';
};

module.exports = base;

Consumers can discover both the inherited getLabel and the added getBadge. This preserves the runtime base object and its other exports. Type precision for an added property depends on the expression and declaration the analyzer can recognize; arbitrary dynamic mutations cannot always produce a precise signature.

Extend an exported constructor

The same relationship matters when the parent exports a constructor rather than a plain object. Preserve the runtime prototype chain explicitly:

app_custom/cartridge/models/productCard.js
var BaseProductCard = module.superModule;

function ProductCard(product) {
    BaseProductCard.call(this, product);
    this.label = product.name || product.ID;
}

ProductCard.prototype = Object.create(BaseProductCard.prototype);
ProductCard.prototype.constructor = ProductCard;

module.exports = ProductCard;

Completion and navigation use the resolved parent export. The editor does not replace the JavaScript needed to call the parent constructor or establish inheritance. How much can be inferred also depends on the base module's declarations and JSDoc.

Extend an SFRA controller

SFRA's server.extend consumes the inherited controller, while append, prepend, and replace express route extensions:

app_custom/cartridge/controllers/Product.js
var server = require('server');
server.extend(module.superModule);

server.append('Show', function (req, res, next) {
    res.setViewData({ showBadge: true });
    next();
});

module.exports = server.exports();

The route index connects these declarations. Route CodeLens can reveal the indexed append, prepend, and replace locations, helping you distinguish the base handler from later route changes.

When the result is unexpected

SymptomCheck
The parent has no useful type or definitionA later active cartridge must contain the same relative module path and be available locally.
The wrong layer is selectedCheck the selected site scope, cartridge order, and linked cartridge locations.
One member is missingConfirm the parent actually exports it; a local function alone is not a CommonJS export.
The editor and sandbox disagreeCompare the deployed cartridge path and code version with the local context.

module.superModule is only meaningful where an override has a parent. Do not assume a base value exists in the last implementation. See Module resolution for the other import styles and Cartridges & overrides for inspecting the chain visually.

On this page