SFRA Features and Components
SFRA is carefully architected so that it's easy to use as a blueprint for your own storefront. Built-in features and components provide a range of options for customizing the site to meet your needs.
SFRA provides an
app_storefront_base cartridge and a
server module. A storefront site uses the SFRA base cartridge and overlay plugin, LINK, and custom cartridge functionality to create a cartridge stack. Define the order of the cartridge stack by configuring the cartridge path in Business Manager.
The base cartridge contains only the functionality common to most sites. You can layer functionality over the base cartridge with plug-in cartridges, LINK cartridges, and custom code cartridges. B2C Commerce provides plug-in cartridges that provide other features, such as gift registries, Apple Pay, product comparisons, and middleware capability. LINK partners, such as PayPal and Bazaarvoice, provide LINK cartridges for third-party integrations. You can create one or more custom cartridges to override portions of the base cartridge and customize the functionality and branding of your storefront site.
app_storefront_base cartridge includes multiple models These models use the B2C Commerce script API to retrieve data from the platform for a functional area of the application, such as orders. The models then construct a JSON object that you can use to render a template.
server module provides objects containing data from HTTP requests, responses, and session objects. The
app_storefront_base cartridge models and
server module objects are guaranteed to be backward compatible between major point releases. The guarantee lets you adopt new features more easily and maintains a clear distinction between base and custom code, which can help you troubleshoot issues and adopt bug fixes.
app_storefront_base cartridge or
server module voids the guarantee of backward compatibility and hinders feature and fix adoption. Instead, use B2C Commerce script methods to extend base cartridge functionality. The JSON objects created by the
server module and the
app_storefront_base models retain their structure and don't change properties between point releases. However, Commerce Cloud Engineering reserves the right to change how these objects are created.
A typical cartridge stack includes several layers, as shown in this table:
|Custom||Adds specific customizations for your brand and organization. Perform all customizations of the base, LINK, and product cartridges in custom cartridges for easy adoption of future features.||Rename all custom cartridges with |
|LINK||Adds third-party functionality to your site. You can integrate features from LINK partners, such as payment providers and tax services.||You can import LINK partner data, such as tax tables or inventory feeds. See specific LINK cartridge documentation for more information.|
|Plug-in||Enhances the ecommerce capabilities provided by Commerce Cloud or anyone else in the Salesforce community. Cartridges provided by Commerce Cloud let you integrate (optional) products and features such as product compare and gift registry.||Plug-ins can create custom objects or data that are specific to a product or feature.|
|Base||Core functionality modified only by the Commerce Cloud team or through contributions to GitHub. The core cartridge includes best-practice code for features used by most customers. In addition to the default features, the base cartridge contains features that can be configured in Business Manager.||Some of the features in the base cartridge are configured in Business Manager, such as pick up in store.|
The following graphic shows a typical cartridge stack:
The cartridge path is always searched left to right, and the first controller or pipeline found with a particular name is used. This behavior allows cartridges earlier on the path to override the functionality of cartridges later on the path. The cartridge path for this stack is:
B2C Commerce provides demo data that lets you view and explore the base cartridge as a working site.
Though cartridge data is imported into B2C Commerce and used by the code in each cartridge, it isn't stored in the cartridge itself.
We highly recommend that you do not modify
app_storefront_base. Instead, create your own cartridge and add it as an overlay in the Business Manager cartridge path. Using an overlay cartridge lets you upgrade to a newer version of SFRA without having to manually cherry-pick changes and perform manual merges. You can still adjust your custom code, but the upgrade and feature adoption process is quicker and less painful.
A server module in the SFRA global
modules folder is globally available and can be required without a path in any controller or script.
The following example requires the
server module in the
modules folder is a separate cartridge, so you can easily upload it to the platform. However, you don't have to include it on the cartridge path. For information on using the
server module, see Extending the Base Cartridge Architecture.
Don't directly extend or customize the
server module. If you customize it directly, B2C Commerce can't be held responsible for changes that are not backward compatible in future versions of SFRA.
However, if you want to extend or customize
server module functionality, you can create your own module and place it in the
modules folder. You can require
SFRA uses a variant of Model-View-Controller architecture. Controllers handle information from the user, create ViewModels, and render pages. The ViewModels request data from B2C Commerce, convert B2C Commerce script API objects into pure JSON objects, and apply business logic.
A ViewModel differs from a standard B2C Commerce script object in the following ways.
- A ViewModel provides the data to render pages in the application and often combines data from multiple B2C Commerce script objects.
ViewModels are also referred to simply as models, because that's the name of the folder where they are located in the application.
SFRA defines endpoints (URIs) with a
Controller-RouteName syntax. Defining an endpoint depends on your controller's filename and the routes defined within it.
The syntax of your endpoint depends on the SEO options you choose for your site. When developing, you can use the Commerce Cloud Standard URL Syntax without SEO options. This approach makes it easy to test your controllers.
Example: Defining an Endpoint for Your Home Page
Suppose that you want to create an endpoint in B2C Commerce standard URL syntax that looks like the following:
You create a
Home.js module in the controller folder with the following code:
Home-Show route consists of the module name (
Home.js) and the first parameter in the
server.get function (
use function takes the
RouteName of the function to execute as the first argument. SFRA provides two utility methods to call the
use function (
server.post) that make sure the URI is either a GET or POST request.
This functionality is different from many other frameworks, which define routes by overriding anchor functionality in the URI to define actions to execute.
When a request is made via a URI in the web browser, the last part of the endpoint specifies the
Controller-RouteName to execute. In this example, the filename is
Page.js and the route name is
Page.js file must be stored in the
controllers folder for B2C Commerce to recognize it as a controller.
When the controller is located, all
require statements at the beginning of the controller are executed. These statements must include a
require for the
server module. The
server module is located in the
modules folder, which is a peer of the
app_storefront_base cartridge. Requiring the
server module returns an empty
The next line to be executed is the following:
This line is present in all controllers. Calling
server.exports() causes the server to register all functions in the controller that use the
server.use functions as routes. The server then executes the function whose first parameter matches the route name in the URI.
For example, if you assume the URI in the previous example that ends in
Page-Show, B2C Commerce registers all functions in
Page.js and then executes the
Suppose that this code is saved to a file named
Page.js file creates a route for a URL.
Whenever that URL is called, the provided function is executed and renders a page with the following
The rendered page also includes the following body:
You can enhance this code by adding the
server.middleware.https parameter after
Show, to limit this route to only allow HTTPS requests. This example restricts the
Account-Show route to HTTPS.
This function is one of the middleware functions provided by Commerce Cloud.
Information about middleware filtering classes is available in the SFRA JSDoc in the server-side global documentation for the
server.post function, the first parameter is always the name of the route (the URL endpoint). The last parameter is always the main function for the endpoint. Usually, the main function in the controller renders a page for the storefront or redirects to another controller.
You can add as many parameters in between the first and last parameter as you want. Each parameter specifies a function to be executed in order and can let the next step be executed (by calling
next() or reject a request by calling
Example 1: Conditionally Executing a Middleware Step
This example shows a main function that conditionally executes
next(new Error()) depending on whether an Apple Pay order is being placed.
The code executed between the first and last parameter is referred to as middleware and the entire process is called chaining. You can create middleware functions to limit route access, add information to the data object passed to the template for rendering, or for any other purpose. One limitation to this approach is that you must call the
next function at the end of every step in the chain. Otherwise, the next function in the chain is not executed.
Each step of a middleware chain is a function that takes three arguments:
next, in that order.
This argument is short for
Request. It contains information about the server request that initiated execution. The
req object contains user input information, such as the content-type that the user accepts, the user's login and locale information, or session information. The
req argument parses query string parameters and assigns them to the
This argument is short for
Response. It contains functionality for outputting data back to the client. For example:
res.cacheExpiration(24): Sets cache expiration to 24 hours from now.
res.render(templateName, data): Outputs an ISML template back to the client and assigns
res.json(data): Prints a JSON object back to the screen. It's helpful in creating AJAX service endpoints that you want to execute from the client-side scripts.
res.setViewData(data): Doesn't render anything, but sets the output object. This behavior can be helpful if you want to add multiple objects to the
pdictof the template. The
pdictcontains the information for rendering that is passed to the template.
setViewDatamerges all the data that you passed into a single object, so you can call it at every step of the middleware chain. For example, you can create a separate middleware function that retrieves information about a user's locale to render a language switch on the page. The output object of the ISML template or JSON is set after every step of the middleware chain is complete.
You can also use the ViewData object to extend the data created in a controller that you are extending. You don't have to duplicate the logic used in the original controller to get the data. You only have to add the additional data to the ViewData object and render it.
next function notifies the server that you are done with a middleware step so that it can execute the next step in the chain.
By chaining multiple middleware functions, you can compartmentalize your code and extend or modify routes without having to rewrite them.
server module emits events at every step of execution and you can subscribe and unsubscribe to events from a given route. Use an event emitter to override the middleware chain by removing the event listener and creating a new one. However, if you have to change individual steps in a middleware chain, we recommend that you replace a route. While SFRA does supply
removeAllListener functions, they don't recognize named event emitters. For this reason, it isn't possible to use
Step event emitters to override a specific step in the middleware chain.
The following is a list of currently supported events:
route:BeforeCompleteis emitted before the
route:Completeevent but after all middleware functions. Used to store user submitted data to the database; most commonly in forms.
route:Completeis emitted after all steps in the chain finish execution. Subscribed to by the server to render ISML or JSON back to the client.
route:Redirectis emitted before
route:Startis emitted as before middleware chain execution.
route:Stepis emitted before execution of each step in the middleware chain.
All events provide both
res as parameters to all handlers.
Subscribing or unsubscribing to an event lets you do complex and interesting things. For example, the server subscribes to the
route:Complete event to render ISML back to the client. If you want to use something other than ISML to render the content of your template, you can unsubscribe from the
route:Complete event. You can subscribe to it again with a function that uses your own rendering engine instead of ISML, without modifying any of the existing controllers.
OnSession event handlers that were implemented as pipelines in SiteGenesis Pipeline Processor (SGPP) and as controllers in SGJC are not used in SFRA. You still have access to request and session data using the middleware
req (request) and
res (response) objects. However, SFRA avoids using OnRequest and OnSession anywhere in our code outside of the
If you want to implement
OnSession, they must be implemented through hooks. B2C Commerce looks for
OnSession as the controller name, but the new architecture doesn't do that. The only difference between a hook and controller is that the hook doesn't have access to the
B2C Commerce owns and maintains the
app_storefront_base cartridge. The base cartridge is hosted on GitHub and anyone can contribute to it through a pull request. We test all pull requests before they are approved.
app_storefront_base cartridge contains controllers for business logic, models with JSON objects populated from the B2C Commerce script API, and ISML templates. It also contains the
modules directory with a
server module for SFRA.
Anything in the
modules folder or
TopLevel package is globally available and can be required without a path. You can add your own custom modules to the
We provide a sample plugin cartridge as part of the SFRA project that demonstrates how to selectively add custom functionality to the base cartridge. Add this cartridge to the left of the base cartridge on the cartridge path to observe the functionality.
Make sure to regularly update your
server module to have access to the most up-to-date security and bug fixes. Regularly updating your base cartridge.