Since Aconcagua 2018.1, a theme has meant a specific thing to SuiteCommerce. It is a special kind of extension that contains your site’s Handlebar templates and Sass styles. If you’re new to this architecture, or SuiteCommerce, then this article explains what a theme is, its anatomy, versioning and activation, making simple changes, and using the theme customizer.

If you want to know more about how the commerce extension framework enables themes, I would recommend reading about The Extension Framework and Extensibility API. We also have comprehensive documentation on themes, which I advise reading.

What is a Theme?

A theme is a special type of extension. Extensions were introduced for Aconcagua and the release of the new SuiteCommerce product: they allow modification to the functionality and/or the look-and-feel of a site without modifying the source code files of a site. Both are enabled or disabled, and then recompiled into the site's final source code, via the extensions manager.

Here are some of their similarities:

  • All files are versioned, and the appropriate files (including images) can be referenced on a version-by-version basis (eg for easy updates and rollbacks)
  • They use similar (but different) development tools
  • Can be easily packaged up for sharing
  • Give a reasonable level of certainty that they'll work regardless of the site and domain they're activated on
  • Activated through the Extension Management page in the UI
  • Neither enable the modification of source code files
  • Mandatory for all SuiteCommerce sites and all SuiteCommerce Advanced sites running Aconcagua or newer

For the purposes of this article, we won't refer to themes as extensions again — it's best to think of them as distinct things. The following table summarizes the differences between a theme and an extension.

Themes Extensions
Alter the design, look, and feel of a specified domain Introduce new functionality or features to a specified domain
Can include HTML, Sass, fonts and images only Can include SuiteScript, JavaScript, configuration files, HTML, Sass, fonts and images
Existing HTML and Sass files are modified directly Existing HTML and Sass files are overridden; new files can be added for new functionality areas
Only one can be active per domain at any time Any number can be active on a domain at any time

It’s important to emphasize that since the architecture of SuiteCommerce and SuiteCommerce Advanced sites are so similar, a theme from one kind of site can be moved and applied to another (whether it is SuiteCommerce or SuiteCommerce Advanced). The technology is the same — the only technical difficulty might be if the theme is for an older version, then there might be some difficulties.

Benefits of Themes

After the initial creation of a theme by a developer, control and customization is moved into the hands of site administrators. To achieve this, we provide a superhero combo of new architecture for devs and a powerful UI for site admins. The new UI comes in the form of the double-act of the extension manager and the theme customizer, which complement the array of tools already available in the site management tools.

What this means is that the developer puts in the hard work to set up a theme: defining the layout of the templates, and setting some initial Sass default values, and then the site administrator can tinker with them to produce the best fit for their vision of what their site should look like.

Furthermore, developers can go further than defining one set of defaults for a theme: they can also include what we call skins. Skins are like a abstraction layer above the theme containing a pre-defined list of values. The idea is that if you like your site's layout, but only want to change the colors and font sizes, then you can save these to a file and allow administrators to easily switch between them. This'll prove useful if you like to refresh your site's appearance for different seasons, or if you have a promotional event on.

In short, themes enable a “set and forget” for developers who can do the initial work to get a look-and-feel live, and then leave it in the hands of business users to make their own changes to through the site management tools. The SMTs enable business users with:

  • Drag-and-drop content, such as blocks of images, texts, banners, merchandising zones, HTML and even custom content types
  • Customizing a theme’s variables, so they can change colors, fonts, font-sizes, padding (any Sass variable can be exposed to the customizer)
  • Skinning, for seasonal or temporary changes to a theme
  • Landing pages for ad-hoc static pages (eg for campaigns or generic static content)
  • Alternative page layouts
  • Timed content, so that changes go live at a certain point (and then get removed automatically at another)
  • And much more

While some of this is available to older sites that don’t operate themes, the point is that so much look-and-feel work that a developer might usually be expected to do is now in the hands of business users, empowering both to get on make changes appropriate to their skillsets.

Theme and Code Updates

If you’re starting from a fresh install, you will have access to the base theme. However, there are a number of other themes available: some are provided by NetSuite and are included with some implementations of SuiteCommerce, and others may be available from third-parties.

The base theme is installed as a bundle, and it is available as an unmanaged bundle. The bundle is updated periodically, usually in line with each release of SuiteCommerce, but it is up to site administrators and developers to update their theme bundle too.

The base theme is a great place to start with creating your own custom theme, but it is worth pointing out that when you customize a theme or create your own one, you become responsible for updating it. This is because the theme becomes ‘locked’ to that version. While it would be straight-forward for a developer to do work each release to bring it back up to date with the latest base version, this is still a maintenance task.

Accordingly, customers should be made aware of this fact before proceeding.

If you run a SuiteCommerce site (ie one where the codebase automatically updates), you may want to rely on a theme that is managed by NetSuite or a reliable third-party. While it is not likely that your site will ‘break’ if you use an older theme, you may find certain parts of your site malfunction or do not have the most recent features ready to use.

The Base Theme and its Anatomy

As with every previous version of SuiteCommerce Advanced, we include a set of templates and Sass files with the release.

When installed on your account, a theme needs to be activated on your site. You will also need to download the theme development tools, which are in the file cabinet, stored where the base theme’s bundle was installed. You must use the specialist theme tools to make modifications to a theme — you can’t use the standard SCA developer tools or the extension developer tools.

After you've installed the bundle, activated the theme, and installed and local theme development tools, you start by fetching the current theme from your site. This is done with gulp theme:fetch.

When it completes, you'll be furnished with a workspace that contains all of the folders and files that constitute your theme. As our docs say, you'll see something like this:


  • Extras/
    • Extensions/
      • application_manifest.json
  • SuiteCommerceBaseTheme/
    • assets/
    • Modules/
    • Overrides/
    • Skins/
    • manifest.json

The Extras folder contains anything related to any extensions that are currently active on your site. For the timebeing, we're going to ignore that folder and instead focus on the contents of SuiteCommerceBaseTheme. Note that this name is dependent on the active theme.


One key change is that we now store fonts and images under a single parent directory away from the modules that depend on them. By default we include two sub-directories: font-awesome and img — one is the only custom font we use, and the other is a catch-all for all the site's base imagery (eg for credit card icons, favicon, etc).

Note, however, you are free to organize your assets as you need to within the assets parent directory. So, if you're going to add a custom font, then create a folder with its name on it; if you want to separate your images into separate folders that make sense to you, do it! They'll be included in your theme's package.


This is the meat of the theme. This is where all of the templates and Sass files that you're familiar will live.

If you're already familiar with SCA development, there isn't much to say about these files and folders. However, one important thing to note is that in theme development we do allow you to edit the source files directly. Go wild.


This isn't a directory for the files within your theme. It is for theme-specific overrides of any extensions your site has.

Picture this scenario: you've got a fancy extension that adds some new functionality to your site, but its layout and styling doesn't conform to the rest of your site. What do you do? Edit the files of that extension? Yuck. No. You put in theme-specific overrides.

This post won't go into the details of this, but if you need this, we have docs on how to do it.


Remember: while you'll build a number of default values into your theme, you can additional sets of default values into skins. A site administrator can swap between skins using theme customizer. But how do we determine what a skin is? The answer is in this folder and let's take a closer look.

If you look at the contents of one of the skins in the base theme, eg skin1.json, you'll see that it's an object of key-value pairs.

"$sc-color-body-background": "white",
"$sc-button-primary-text-color": "white",
"$sc-button-primary-hover-text-color": "white",
"$sc-button-primary-active-text-color": "white",
"$sc-button-primary-text-transform": "none",

The keys are a number of 'editable' Sass variables that are present throughout the theme and the values are the values we want to change them to.

What happens is that when a user enters the SMTs and selects a skin, it loads the JSON blob, substitutes the values in the theme, and then recompiles on-the-fly. This allows for rapid switching and previewing of a color scheme (plus any other style changes to fonts, spacing, etc).

Creating your own skin can be as simple as copying an existing JSON blob in a theme and putting in your own values. Any JSON file within the Skins folder will be caught by Gulp when you deploy, and will be automatically added to the manifest file. It will automatically take the name of the JSON file (eg, a file called skin9000.json will be named skin9000) but you can change this in the manifest. If you want, you can compile just the manifest file and then change the name of it to whatever you want before you deploy.

However, if you're working on a new skin that includes previously unreferenced variables then you should know that it's not enough to simply include your variables in your skin to make them configurable in the SMTs — you must also mark up your code too. We'll look at this later.


I've mentioned this a couple of times already, so let's take a look.

As I say in my post on the commerce extension framework, extensions and themes don't use ns.package.json and distro.json files anymore (well, distro files are still present, but you don't need to worry about them). Instead, we now use manifest files.

Manifests work like the two of them combined, with the added benefit of them being automatically updated when the compilation process runs. You will need to manually edit them to specify some things, such as the metadata of the themes and skins, but generally it means you don't have to manually include every file that you want to be included in your project.

You can prevent manifests from being updated automatically by using a flag when you deploy.

Versioning and Activation

I've talked about this in the introductory blog post on extensibility, so I won't reiterate it here in great detail. Suffice to say, themes (like extensions) are not automatically applied to a site when you deploy the code to NetSuite: they must be activated first. Activation recombines the site's source code to create the final output. Only one theme can be active on a site at a time.

Also, when I say 'site' I mean, strictly speaking, 'domain'. Themes and extensions are activated on a per-domain basis. This means that if you want to set up a secondary SSP on which to do development work, or to simply create other façades for your inventory.

Referencing Assets

One thing I do want to reiterate and go into greater detail about are how we handle paths to assets across versions.

Consider this scenario: your theme contains imagery. That imagery changes across different versions, so what happens? Do images gets overwritten? No. They're stored in separate folders, just like all the other files in a theme.

So, how do you generate links to them when they have same names? New helpers! In total, there are four new Handlebars helpers for your HTML and two new Sass helpers for your styles.

These helpers provide and maintain dynamic paths to the assets. Our documentation goes into detail about the what, how and when of these helpers, but here's a summary:

Helper Type Customization Type Name
Handlebars Extensions getExtensionsAssetsPath(default_value)
Handlebars Extensions getExtensionsAssetsPathWithDefault(config_value, default_value)
Handlebars Theme getThemeAssetsPath(default_value)
Handlebars Theme getThemeAssetsPathWithDefault(config_value, default_value)
Sass Extensions getExtensionsAssetsPath($asset)
Sass Theme getThemeAssetsPath($asset)

The primary use in templates is when you would call an image whose full relative path hasn't been defined by the view. For example, in the homepage template we have fallbacks for when no images are defined in the site configuration that look like this:

<!-- Example code -->
<img src="{{getThemeAssetsPath (resizeImage 'img/carousel-home-1.png' ../imageHomeSize)}}"/>

<!-- Translated output -->
<img src="/c.123456789/scs/extensions/SuiteCommerce/Suite_Commerce_Base_Theme/18.1.1/img/carousel-home-1.png">

So you're saying that the image is the one in the images folder with this file name, now provide the path required to access it on the frontend.

To use a Sass example, let's say we wanted to add a background image to an element — an image that could change depending on the version of the theme, you would mark up your file as follows:

// Example code
.myClass {
    background-image: url(getThemeAssetsPath('img/flowers1.jpg'))

// Translated output
.myClass {
    background-image: url(/c.123456789/scs/extensions/SuiteCommerce/Suite_Commerce_Base_Theme/18.1.1/img/flowers.jpg)

Thus, they work the same way.

If you're wondering what the difference between a normal helper and one 'with default' — essentially, you use them in cases where a user may specify a value in the site's configuration record, but you want to include a fallback value in case. A good example of this is in creditcard_edit_form_securitycode_tooltip.tpl:

<p><img src="{{getThemeAssetsPathWithDefault imageCvvAmericanCardURL 'img/cvv_american_card.jpg'}}"></p>

This appears on the credit card form when we ask a shopper for their CVV code. We want to show an image of where to find this on Amex cards. The location for this image is a configurable option — a site administrator can easily change the image and location of it in NetSuite — but, what if the value is cleared? Well, we can show a fallback image that we include in the theme.

Finally, it is worth mentioning that the custom Handlebars helpers can be used in your JavaScript too, if you wish (they are, after all, simply JavaScript functions). Be sure to add Handlebars.Extras as a dependency to your file first.

Working Locally

Themes and extensions have separate working environments from each other and from SCA. Depending on what you're working on, you will need to spin up a local server that is contextual to that. However, when you work on an extension you'll always start by grabbing the site's active theme, and when you work on a theme, you'll grab the site's active extensions. This, therefore, means that you'll never be working on something in complete isolation.

You can read more on testing a theme on a local server in our documentation.

There are three key Gulp commands for working locally:

  1. gulp theme:local — spins up the standard local server
  2. gulp theme:local --preserve-manifest — spins up the local server without updating the manifest
  3. gulp theme:local styleguide — spins up the local server, and a second local server for viewing the live style guide

As always, the URL of your local server is dependent on your site's configuration and whether you're running SC or SCA.

Preserving the manifest with the flag can be useful if you're tinkering around with your file structure and only want specific files included, for example with debugging. If you want to exclude a file without manually editing the manifest, then you'd need to move it out of your workspace, which could be a bit of a hassle.

Prepare for a New Theme

Let's get started.

For the purposes of this, I'm going to work with the NetSuite base theme. If you already have a custom theme that you want to modify, then you can follow along with that but some things may be different.

Fetch the Active Theme

OK, so at this point you've done all the basic install steps, like installing the bundles, grabbed the developer tools and unzipped them, installed Gulp and Node. The first thing you need to do is navigate to the parent folder for the theme developer tools in your CLI and run gulp theme:fetch. This command will pull down a site's active theme. Note that this will overwrite any files you have in your workspace, so I strongly recommend that, in future, you only run this when you're happy to lose what you're currently working with.

Create the New Theme in NetSuite

If this is a brand new theme (which in this example it is) then we need to begin by creating a record of it in NetSuite. To do this, we run gulp theme:deploy --create. From there you will be asked a series of questions about the metadata of your new theme.

Once it has been deployed, you'll be given some feedback about next steps; ie, how to activate it on your site so that it takes effect. However, at this point, seeing as your theme is just a copy of the existing theme with no modifications, we can skip that.

You will notice, however, that your local files have been renamed and updated to match the name that you specified. For example, my theme's directory is now called My_Super_Cool_Theme and the metadata at the top of the manifest file looks like this:

    "name": "My_Super_Cool_Theme",
    "fantasyName": "My Super Cool Theme",
    "vendor": "Dave Smith",
    "type": "theme",
    "target": "SCA,SCS",
    "version": "1.0.0",
    "target_version": {"SCA":">=19.1.0","SCS":">=19.1.0"},
    "description": "This is my first theme and it's super cool",

Great stuff!

Versioning with VCS

Now that you have the theme, this might be a good time to start versioning it locally. I've talked about it loads of times before but if you're not already using something like Git to version your code, I strongly suggest you get started with version control. It could save you some serious headaches.

If you've got Git installed and ready to go, let's proceed; if you're not going to version your code, you can skip this section.

So, one question I've been asked is how much of an extension or theme's code you should version. For example, should you include the distribution folders? What about the node_modules folder? Including those would certainly make your repo more 'complete' but you may end up with quite noisy commits.

Look, my suggestion is that you only version the source code that compiles into the theme and nothing else. Therefore, you need the contents of your theme's directory only; eg, for me, that would be SCA-THEME > Workspace > My_Super_Cool_Theme.

In order to do this, we'll need to make use of gitignore, a way of telling Git to intentionally ignore certain folders and files.

In your parent directory (which I've called SCA-THEME), create a file called .gitignore and in it put:

# exclude everything except for Workspace/<theme>

For details on what's going on here, take a look at their documentation but I'll summarize:

  1. (The first line is just a comment to us)
  2. Ignore everything!
  3. Except the Workspace directory
  4. But then ignore everything in there!
  5. Except the My_Super_Cool_Theme directory

Then, in your command line, run git init; when that's done, run git status — you should see this:

$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)


nothing added to commit but untracked files present (use "git add" to track)

Running git add . and then git status will give you a long list of green text, itemizing all of the goodness we're going to be saving. Crucially, they should be within the Workspace/My_Super_Cool_Theme directory. If they are, and you're happy, go ahead and do git commit -a -m "Super Cool Theme -- initial commit".

Great! That's it. If you have a remote repository, such as GitHub or Bitbucket, then you'll need to do the extra steps for push it up to there, but for now we can move on!

Create a Theme

OK, let's make our first changes. For the purposes of this tutorial, I'm not going to create an entirely new theme — that would be a lot of work! — but what I am going to do is a number of small changes to illustrate the beginnings of a new theme. You could take it from there if you like.

Add an Image

I'm going to start with something simple: I want to show a big banner image on my homepage. How do I do that?

First, I've prepared my image, it looks like this:

An example banner image showing an astronaut orbiting above earth with the words "Our prices are out of this world!" imposed on top

I'm going to go ahead and add it to assets > img.

Now, I need to edit my homepage template.

In Home > Templates > home.tpl, add the following near the top (eg above the slider):

<div class="home-banner-prices">
    <img class="home-banner-prices-image" src="{{getThemeAssetsPath (resizeImage 'img/themepricesoutofthisworld.jpg' homeslider)}}">

After saving, run gulp theme:local.

Gulp automatically adds the file to the manifest and spins up the server. When it's up, visit your local homepage and you should see something like this:

A screenshot of the banner image on the homepage

Great stuff. But, it looks a little cluttered: the banner top message is right on top of it, and we need a little margin to space it out nicely.

Add Styling

In Home > _home.scss, add in:

.home-banner-prices {
  margin-top: $sc-margin-lv4;
  font-size: 0;

As the local server is still running, it will recompile the site's files when you save. When it's done, refresh the homepage and revel in how well spaced out your new banner is!

Add a Customizable Color

You know, this banner image looks great but I think it would look even better if it had a luminescent glow around it. You know, really make it look eye-catching. Furthermore, I don't want to dictate what this color is: I want my site administrator to be able to decide. How do I do this?

If we want to expose a variable for customization, we need to add (or find) the variable in the Sass file and then put a special comment next to it. The comment must contain a properly configured editable() function to get picked up the preprocessor.

Let's do this properly and add a new module for our customization.

In Modules, create a folder called Glowy\@custom-1.0.0 and then another below it called Sass.

In that child folder, create _glowy.scss and in it put:

$color-glowy: #3bfbfd; /* editable({
    "type": "color",
    "label": "Glowy Color",
    "description": "For when you want extra glowy stuff"

@keyframes glowy {
  0% {box-shadow: 0 0 -10px $color-glowy;}
  20% {box-shadow: 0 0 100px $color-glowy;}
  40% {box-shadow: 0 0 200px $color-glowy;}
  60% {box-shadow: 0 0 200px $color-glowy;}
  80% {box-shadow: 0 0 100px $color-glowy;}
  100% {box-shadow: 0 0 -10px $color-glowy;}

.glowy {
  animation: glowy 1500ms infinite;

So, the first bit is the editable color. Note I've set an initial value and then put a comment with an editable() state function in it, where I set some metadata around this variable. It’s important to note that while it just looks like a regular comment, it’s required to make the variable editable via the SMTs — it’s what it looks for!

The next bit is just a bit of fun, I'm going to make the image glow and I want it to be animated, so these are the 'keyframes' of the animation.

Finally, the .glowy class is what we will use to attach the animation to an element.

Import a Sass File into Another

Now we have that set up, we need to add it to the entry point Sass files for the applications we want to use it in. By doing this we are ensuring that the Sass we have written gets rolled into the ‘master’ Sass file for the application.

Open Shopping > shopping.scss and add in the following:

@import "../Glowy@custom-1.0.0/Sass/glowy";

Finally, we need to modify our homepage Sass so our element uses our new styles. Tab back to _home.scss and add in:

.home-banner-prices-image {
  @extend .glowy;
  width: 90%;
  margin: 5%;

Great! Save and then stop and start your local server (you've added new files, so they need to be tracked). When it's up again, refresh your homepage and take a look. It should look like this:

An animated demonstration of the banner image with a glowing border around it


Add a Custom Variable to a Skin

Now that we have this, we can add it to a skin so that it can be manipulated by a site admin. If you want, you can also use this opportunity to create an entirely new skin (starting by duplicating an existing one), but for now we can just tinker with the existing ones.

In your theme's folder, open up skin1.json, scroll down and add:

"$color-glowy": "red"

Don't forget to add in a comma on the end of the previous line.

Open up skin2.json and do the same, this time replacing red for green.

So, remember what we're doing here: the theme default color is what we originally set $color-glowy to; in the skins, we have new values (red and green) that are only activated if the administrator selects them in theme customizer.

Update Manifest and Deploy

Great! We're now ready to test this out. First, you should update the version in the manifest — we're going to create a new version of our theme!

Open manifest.json, and change the value of version to 1.0.1.

After saving everything, run gulp theme:deploy.

When that's done, activate the new version of your theme.

Finally, head over to your homepage and load up the site management tools. Once it's fully loaded, click the cog icon and select themes.

Theme Customizer

The theme customizer allows any administrator to change the values of any exposed Sass variable. Take a look at the options.

You'll notice that there's a Palette section, which lets you change the master groups of colors associated with your site. Then, as you scroll down, the options will get more granular. For example, you could change the primary color of the theme, but then override that for headings.

You'll also notice that some of the options are grouped up, and that some have pre-defined options: these are additional features that you can build into your Sass stylesheets if you like.

To get an idea of groupings, open BaseSassStlyes > Sass > reference-theme > _groupings.scss and take a look. For example:

    "id": "typography-h1",
    "label": "Heading 1",
    "description": "",
    "children": [

Which translates into:

A screenshot of the site management tools showing a group of configurable styles

If you're interested in creating your own marketable themes, you should definitely consider putting in the work to create neat little groupings. You could also create a custom area in the styleguide too.

Anyway, we're here to test our new glowy banner. You should see that the glowy banner is in a light blue color, which is the default we set in the theme. Now, if you scroll down to the bottom of the customizer, you can see our new option available.

A screenshot of the site management tools showing our new group of configurable styles for the glowy element

Feel free to change the value; try red, green, pink, whatever you want. The cool thing is that it will change it realtime before your very eyes.

A gif demonstrating different color changes to the glowing border as they are updated in the site management tools

Finally, while we're here: you can change the skin. Remember, we put in new variables for each skin, so you can change them and watch it take effect.

If you want to keep one, you can save the changes and it'll take effect on your site straight away.


There aren't many problems specific to themes, but here are some you may encounter.

Cannot Access Theme Customizer in the Site Management Tools

When logged into the SMTs, you can access the theme customizer by clicking on the cog icon and selecting Themes from the dropdown. If the theme customizer is not detecting customizable themes or skins, it won't be available and clicking the cog will take you straight to a list of your site's content types (without showing you the option for the theme customizer).

At this point, we're not entirely sure why the link doesn't show up when it should but we have found a workaround.

  1. In NetSuite, search for the skins associated with your theme (eg, search for skin1.json, skin2.json, etc)
  2. Edit and save each record
  3. Edit and save each JSON file for each skin
  4. Invalidate the cache for the domain

The link to the theme customizer should now appear in the SMTs when you refresh your browser.

Exposed Variable Metadata Doesn't Load

This is something I discovered while tinkering: you've configured your new Sass variable to be configurable via the theme customizer, but when you get there, it doesn't look right, eg:

A screenshot of the site management tools which shows that the metadata for this particular configurable element has not loaded properly

If you open up the developer console, you might see something like this:

A screenshot of the developer tools in the command line showing an error being returned, which says that it couldn't parse the JSON properly

In my early iteration, I realized that I had not put commas in my JSON object and so it couldn't parse each of the key-value pairs. So! Check your JSON, make sure that you've coded it correctly.