Cartridges and cartridge paths
Cartridges are the basic units used to organize and deploy application code in Salesforce Commerce Cloud. A cartridge path selects cartridges for a site and defines their precedence.
These concepts belong to the platform, not to Commerce Klaus. The tools use them consistently so local analysis and tests follow the same structure as the SFCC script runtime.
What is a cartridge?
A cartridge is a named directory with a cartridge/ subdirectory. It can contain server-side JavaScript, templates, static assets, forms, configuration, and metadata:
cartridges/
└── app_custom/
└── cartridge/
├── controllers/
├── scripts/
├── templates/
└── static/app_custom is the cartridge name. The outer cartridges/ directory is only a project convention for keeping multiple cartridges together; it is not itself a cartridge.
Cartridge names often communicate a role, for example app_*, int_*, or bm_*. These prefixes are conventions. They do not establish dependencies or precedence by themselves.
What is a cartridge path?
A cartridge path is the ordered list of cartridges active for a site or tool invocation. Salesforce commonly represents it as a colon-separated value:
app_brand:app_core:app_storefront_base:modulesRead the path from left to right:
app_brandhas the highest precedence.app_coreis considered next.app_storefront_basefollows.moduleshas the lowest precedence in this path.
The order is application behavior, not a display preference. If more than one cartridge provides the same resolvable resource or registration, the first applicable entry wins.
Cartridge order is behavior
Do not alphabetically sort or deduplicate an explicit cartridge path. Changing the order can change which implementation the platform uses.
How overrides work
Suppose the project contains:
cartridges/
├── app_brand/cartridge/scripts/price.js
├── app_core/cartridge/scripts/price.js
└── app_storefront_base/cartridge/scripts/price.jsWith this path:
app_brand:app_core:app_storefront_basethe effective */cartridge/scripts/price module comes from app_brand. Removing app_brand from the path or moving it behind app_core changes the selected module without changing the importing source.
The same first-cartridge-wins principle matters beyond ordinary modules. Cartridge order can determine effective hook registrations, job step type IDs, and other metadata-driven contracts. module.superModule also follows the path, but starts after the current cartridge to find the next implementation.
The path does not imply that every cartridge depends on the cartridge to its right. It only defines precedence for platform lookups that use cartridge order.
Cartridge directory and cartridge path are different
Commerce Klaus commonly exposes both concepts as configuration:
import { defineConfig } from "@commerce-klaus/config"
export default defineConfig({
cartridgesDir: "cartridges",
cartridgePath: ["app_brand", "app_core", "app_storefront_base", "modules"],
})cartridgesDirtells tools where cartridge directories are stored on disk.cartridgePathtells tools which cartridges participate and in which order.
A cartridge can exist below cartridgesDir without being part of the effective path. This is common for test cartridges, Business Manager extensions, integrations, or cartridges used by another site.
Cartridge paths are site-specific
An SFCC instance can host multiple sites with different cartridge paths. A cartridge available in the code version is not automatically active for every site.
Site-template metadata can declare a site's path through the custom-cartridges value in:
sites/site_template/sites/<site-id>/site.xmlCommerce Klaus can read this metadata when siteTemplatePath and site are configured. For local tools and CI, an explicit central configuration is also useful when the deployed site metadata is not part of the repository.
How Commerce Klaus determines the order
Commerce Klaus uses the following precedence when determining cartridge order:
- An explicit
cartridgePathoption. - An
envCartridgePathoption, the SalesforceSFCC_CARTRIDGESenvironment variable, or the legacySFCC_CARTRIDGE_PATHenvironment variable. - References in the configured solution
jsconfig.json. - The site's
custom-cartridgesvalue insite.xml. - A deterministic alphabetical filesystem fallback.
The first source that produces entries wins. SFCC_CARTRIDGES takes precedence over SFCC_CARTRIDGE_PATH, and both comma- and colon-separated values are accepted. Missing cartridge directories are filtered out, and valid results are represented internally as absolute cartridge-root paths.
For reproducible CI and local behavior, prefer an authoritative project source such as an explicit path, solution references, or site metadata. The alphabetical fallback is convenient for initial setup, but it cannot express intentional override precedence.
Use the project configuration to define a shared cartridgesDir, explicit cartridgePath, or site metadata source for all Commerce Klaus packages.
How the path affects module identifiers
Cartridge-aware module identifiers use the current path in different ways:
| Module form | Meaning |
|---|---|
*/cartridge/... | First matching module in cartridge-path order |
~/cartridge/... | Module in the importing file's cartridge |
<cartridge>/cartridge/... | Module from one explicitly named cartridge |
module.superModule | Next matching implementation after the current cartridge |
dw/... | Platform API module; not a file from the cartridge path |
Continue with SFCC module resolution for file candidates, relative modules, SFRA's server module, and detailed module.superModule behavior.
Practical rules
- Preserve the declared order exactly.
- Keep the same authoritative path in editors, tests, CI, and deployed site configuration.
- Do not infer dependency relationships from directory layout or naming prefixes.
- Do not assume that every cartridge below
cartridgesDiris active. - Prefer an explicit path or site metadata over the alphabetical tooling fallback.
- Treat path changes like code changes: review and test their behavioral impact.