Spartacus Development Standards and Coding Guidelines

Table of Contents


Standards have a positive impact on any business – and software development is no exception. An organisation-wide internal style guide for writing code should be accessible to every development team before starting a project.

Coding standards or coding guidelines make sure that all developers working on a project use certain guidelines for coding. It is important to have those standards as developers read code more than they write. Coding guidelines help to make reading code more straightforward. They also make debugging easier as code based on coding guidelines is more homogeneous and consistent.

Writing coding guidelines for a new system is even more crucial as documentation often doesn’t include coding practices that are suitable for code development based on the new system. When guidelines are defined in a document, rules don’t need to be explained to each developer individually, which saves time and effort. It is also essential for onboarding new developers.

I experienced it first hand while working on a commercial project based on Spartacus. Spartacus is a lean, Angular-based JavaScript storefront for SAP Commerce Cloud. Spartacus talks to SAP Commerce Cloud exclusively through the Commerce REST API. Being an open source project, I managed to learn Spartacus and use it for a mid-large scale project with a team of 3 developers, mostly benefiting from Spartacus’ documentation and developer community on Slack and Stackoverflow.

After writing Angular apps since its early versions, I’ve developed my own style, which is strongly influenced by the Angular styleguide, best practices shared by leaders, and simply experimenting with small personal projects.

While working on the Spartacus-based project, I realised that even though our team did implement the Angular style guide, there was no overarching coding standard that covered both coding language (Angular) and the system (Spartacus). Therefore, I believe there is a need for a coding standard that covers both Angular and Spartacus to ensure consistency is maintained. The below Spartacus coding style guide shows best practice examples, common mistakes and tips and tricks to read and write Spartacus code successfully. 

Document Vocabulary

Each coding guideline describes either good or poor coding practice. The wording of each guideline indicates how strong the recommendation is. Before starting the coding process, every developer must ensure they read and follow the below.

Do Guidelines should always be followed. These guidelines form the basis for Spartacus development and need to be implemented. It would take an unusual case to break a Do Guideline. In those cases, a senior consultant should be asked. Green boxes indicate Do Guidelines.

Consider Guidelines should generally be followed. If there is a good reason to deviate, then the guideline can be overlooked - as long as consistency is kept. Blue boxes indicate Consider Guidelines.

Don't Guidelines define code standards that should be avoided. Red boxes indicate Don't Guidelines.

Project Structure

Folder Structure


Try keeping the same component structure as Spartacus’ codebase. However, if you are customising, use “custom” suffix before naming the component or service. Why? Having two classes with the same name can cause confusion during run time. For example,

is a Spartacus service. If you need to customise it, create a service called
and extend the ActiveCard service in your newly created custom service.

					export class CustomActiveCartService extends ActiveCartService {…}


Create the following folders in the codebase to make sure that our Spartacus projects are consistent. The folder structure for components should follow Spartacus’ folder structure to make sure files are created with the same hierarchy. This will help to find the relative Spartacus code more easily.

Data Structure


1. Create interfaces only if you are extending Spartacus’ existing interfaces. Add

prefix to the original name of the interface. Below is an example of extending an existing interface.
2. All new properties should be optional to make sure it is flexible enough to be shared in different contexts or components.

					import {Address} from '@spartacus/core';
export interface ICustomAddress extends Address
     addressUnit?: string;
     billingAddress?: boolean;

The above example extends the ‘Adress’ interface and adds two optional properties.


1. Use classes instead of interface if you introduce a custom component specific data model. Classes are object factories and can be used to create objects and initialise properties, whereas interface defines the objects' type and properties.
2. Use strong types based on the custom interface for Application Programming Interface (API) purposes to ensure UI follows the new custom interface. Otherwise UI objects might only refer to the original properties in the interface and not to the newly added properties.

Recommended Development Environment

CLI Tools

Your Angular development environment should include the latest version of the following tools:


I recommend VSCode as preferred IDE. You can download it from

Editor Settings

In order to make sure that all team members have the same experience, create
folder at the start of your project. In your folder create a
file. Settings added here are known as
settings. Here are some recommended workspace settings that also help to avoid collision with the recommended code-formatter:
  // Prettier uses single quotes.
  "prettier.singleQuote": true,
  // Prettify on save
  "editor.formatOnSave": true,
  // prettier uses 2 spaces instead of 4
  "editor.tabSize": 2,
  // organize imports on save
  "editor.codeActionsOnSave": {
    "source.organizeImports": true
  // Uses the project specific typescript version.
  "typescript.tsdk": "node_modules/typescript/lib"

Editor Extensions

Browser Compatibility


Use the below template to align with testers on supported browsers and devices.

Browser Compatibility Matrix
Devices Matrix

Look into the latest supported browsers by the Spartacus team.


Don’t accept support for any browser or device that is not supported in the browser compatibility matrix as it introduces the risk of unresolvable bugs.

Customising Routes

When a new component is added to Spartacus, routes should be defined in a separate module that contains routing specifications.


Create a folder named custom-routes and create the module name

, which introduces the custom routes.

Here is an example of a custom routing module:

					const STATIC_ROUTES: Routes = [
    path: 'style-guide',
    component: StyleGuideComponent,
    canActivate: [CmsPageGuard],
    data: { pageLabel: '/order'},

  declarations: [],
  imports: [
      routing: {
        routes: {
          creditClaims: {
            paths: ['my-account/creditClaims']
          createCreditClaimOrder: {
            paths: ['my-account/createCreditClaimOrder/:orderCode',
    } as RoutingConfig)
export class CustomRoutingModule { }

The below shows a good example of using routingService:

      cxRoute: CustomRoutes.ORDER_HISTORY

1. Use a separate variable for static routes (if it is necessary to use them at all). Refer to the STATIC_ROUTES variable example above.
2. Create an enumerated data type (enum) for custom route names to make sure you can address names properly in the code.


Don’t use static routes when using routingService. Below you can see an example of using redirect poorly.

      cxRoute: 'createCreditClaimOrder'

Lazy Loading Modules

Lazy loading lets you divide your JavaScript code into multiple chunks. Only deliver related chunks. A chunk is a resource file that is downloaded by the browser when a user views the web page.


Use lazy loading modules as much as possible as it increases the speed of render and makes app function better when it gets bigger. Below is an example of a good lazy loading practice.

  featureModules: {
    organization: {
      module: () =>
          (m) => m.creditClaimsModule
      cmsComponents: [

Create a module according to Spartacus’ codebase. Usually, every component is associated with a module. However, in some cases there might be more than one component attached to a module.


Don’t create a feature module and import all modules in it as it goes against lazy loading.
Don’t add a component directly to the app module.


Use the compdoc package for dynamic documentation purposes. The documentation covers the structure of the application, data models and modular design.

Use the below command to create the document before every release.

					compodoc -p tsconfig.json -s

Leaving comments in code whenever you customise a Spartacus component.

					import { Component, OnInit } from '@angular/core';
import { CmsProductReferencesComponent, ProductReferenceService } from '@spartacus/core';
import { BREAKPOINT, BreakpointService, CmsComponentData, CurrentProductService, ProductReferencesComponent } from '@spartacus/storefront';
import {UserPermissionService} from '../../../services/user-permission/user-permission.service';
 * This is CustomProductReferencesComponent
 * This component extends ProductReferencesComponent
  selector: 'app-custom-product-references',
  templateUrl: './custom-product-references.component.html',
  styleUrls: ['./custom-product-references.component.scss'],
export class CustomProductReferencesComponent
  extends ProductReferencesComponent
  implements OnInit {
     * ProductReferencesComponent dependencies: cmsComponentData, currentProductService, productReferenceService
    protected cmsComponentData: CmsComponentData,
    protected currentProductService: CurrentProductService,
    protected productReferenceService: ProductReferenceService,
    private breakpointService: BreakpointService,
    public userPermissionService: UserPermissionService
  ) {
     * injecting services
    super(cmsComponentData, currentProductService, productReferenceService);
     * Defines width of a carousel item
  public carouselWidth: string = '25%';

  ngOnInit(): void {

     * Set number of carousel items in desktop, tablet and mobile view

    this.breakpointService.breakpoint$.pipe().subscribe((pageSize) => {
      if (pageSize === BREAKPOINT.lg || pageSize === BREAKPOINT.xl) {
        this.carouselWidth = '285px';
       if (pageSize === {
        this.carouselWidth = '285px';
       if (pageSize === BREAKPOINT.xs) {
        this.carouselWidth = '300px';


Avoid leaving comments that are not specific. Comments should clearly specify the intention of variables, methods, services etc.

Share the article with your peers!