dist/codex/salesforce-commerce/skills/node-backend/SKILL.md
Build Node.js backends for Salesforce Commerce — SFCC server-side JavaScript (not actual Node.js runtime), PWA Kit backend (Express-like SSR server), Commerce SDK for server-side SCAPI access, and async patterns for external service integration. Use when building server-side commerce logic.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins node-backendInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Always fetch the latest official documentation BEFORE building server-side logic:
https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-commerce-script-apihttps://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/getting-started.htmlhttps://www.npmjs.com/package/@salesforce/commerce-sdkVerify API methods, module paths, and runtime constraints against current documentation before writing any code.
WARNING: SFCC uses a Rhino-based JavaScript engine, NOT V8/Node.js. Code that works in Node.js will fail in SFCC. Never assume Node.js APIs or patterns are available.
| Feature | SFCC (Rhino) | Node.js / PWA Kit |
|---|---|---|
| Runtime engine | Rhino (Java-based) | V8 |
| npm packages | NOT available | Available |
| async/await | NOT available | Available |
| Promises | NOT available | Available |
| ES6 modules (import/export) | NOT available | Available |
| Filesystem access | Only via dw.io (IMPEX sandbox) | Full fs module |
| HTTP client | dw.net.HTTPClient only | fetch, axios, etc. |
| Module system | CommonJS-like (require()) | CommonJS or ESM |
| var vs let/const | var only (Rhino) | let, const, var |
| Arrow functions | NOT available | Available |
| Template literals | NOT available | Available |
| Destructuring | NOT available | Available |
| Classes (ES6) | NOT available | Available |
| for...of loops | NOT available | Available |
| Mistake | Why It Fails | Correct Approach |
|---|---|---|
| const x = ... | Rhino does not support const | Use var x = ... |
| arr.forEach(item => ...) | No arrow functions | Use function(item) { ... } |
| `Hello ${name}` | No template literals | Use 'Hello ' + name |
| async function f() | No async/await | Synchronous code only |
| require('lodash') | No npm packages | Use dw.* APIs or bundle in cartridge |
| import x from 'y' | No ES6 modules | Use require('y') |
All SFCC server-side functionality is provided through the dw.* namespace:
| Namespace | Purpose | Key Classes |
|---|---|---|
| dw.web | Request/response, URL generation, i18n | Resource, URLUtils, FormElement |
| dw.catalog | Product search, catalog management | ProductMgr, CatalogMgr, ProductSearchModel |
| dw.order | Basket and order management | BasketMgr, OrderMgr, ShippingMgr |
| dw.customer | Customer profiles, auth | CustomerMgr, AuthenticationManager |
| dw.system | Transaction, logging, session, site | Transaction, Logger, Session, Site |
| dw.net | HTTP callouts, FTP, email | HTTPClient, FTPClient, Mail |
| dw.io | File I/O (IMPEX sandbox only) | File, FileReader, FileWriter, XMLStreamReader |
| dw.crypto | Encoding, hashing, encryption | Encoding, MessageDigest, Mac |
| dw.util | Collections and utilities | ArrayList, HashMap, Iterator, Calendar |
| dw.content | Content management | ContentMgr, ContentAsset |
| dw.campaign | Promotions and coupons | PromotionMgr, CouponMgr |
| dw.value | Money and quantity types | Money, Quantity |
All database modifications in SFCC must be wrapped in Transaction.wrap() for atomicity. If any statement inside the transaction throws, all changes are rolled back. Transactions are implicit for job steps but must be explicit in controllers and hooks.
Scripts live in cartridges at cartridge/scripts/ and export functions via module.exports. Use the */cartridge/ prefix for cross-cartridge imports that follow the cartridge path overlay. The cartridge path is configured in Business Manager and determines module resolution order.
Controllers in SFRA (Storefront Reference Architecture) live at cartridge/controllers/ and use the server module to define routes. Controllers handle HTTP verbs (get, post, use) and render templates or return JSON.
PWA Kit runs on actual Node.js (V8) via Salesforce Managed Runtime. It uses an Express-like server created with @salesforce/pwa-kit-runtime. Full modern JavaScript (async/await, ESM, npm packages) is available.
| Aspect | Detail |
|---|---|
| Server creation | createApp() from @salesforce/pwa-kit-runtime/ssr/server/express |
| Data fetching | getProps() static method on page components |
| Configuration | config/default.js with environment overrides |
| Deployment | Salesforce Managed Runtime (auto-scaling, CDN) |
| Custom middleware | Express-style app.use() and app.get() |
| Environment variables | Set via Managed Runtime dashboard |
The @salesforce/commerce-sdk npm package provides TypeScript-typed clients for all Shopper APIs:
| Client | Purpose |
|---|---|
| ShopperProducts | Get products, categories, recommendations |
| ShopperSearch | Product search with facets, sorting |
| ShopperBaskets | Create/update baskets, add items, apply coupons |
| ShopperOrders | Create orders from baskets |
| ShopperCustomers | Customer registration, login, profiles |
It handles SLAS authentication automatically via helpers.getShopperToken(). All SDK methods return Promises. Use Commerce SDK typed clients instead of raw HTTP calls to SCAPI for type safety and automatic auth management.
Pattern: SFCC script module
var ProductMgr = require('dw/catalog/ProductMgr');
var Transaction = require('dw/system/Transaction');
module.exports.execute = function(params) {
// Fetch live docs for dw.catalog.ProductMgr API
};
Pattern: PWA Kit getProps server-side fetch
ProductDetail.getProps = async ({ params, api }) => {
const product = await api.shopperProducts.getProduct({
parameters: { id: params.productId }
});
return { product };
};
Pattern: SFCC HTTPClient callout
var httpClient = new (require('dw/net/HTTPClient'))();
httpClient.open('POST', endpoint);
httpClient.send(JSON.stringify(payload));
// Fetch live docs for dw.net.HTTPClient response handling
Pattern: SFCC Transaction.wrap
var Transaction = require('dw/system/Transaction');
Transaction.wrap(function() {
// All database modifications are atomic here
// Fetch live docs for Transaction rollback behavior
});
var (not let/const), function expressions (not arrows), and try/catch (not Promises)Transaction.wrap()dw/system/Logger for logging -- never console.log (it does not persist)cartridge/scripts/lib/ -- no npm availablegetProps() for SSR data fetching, Commerce SDK hooks for client-side dataconfig/default.js and environment-specific overridesdw.system.Logger error logging at appropriate levelsPromise.all() in PWA Kit for independent API callsFetch the latest SFCC Script API reference and PWA Kit developer guide for exact method signatures, runtime constraints, and deployment procedures before implementing.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.