The extension framework and extensibility API have been available since the Aconcagua (2018.1) releases of SuiteCommerce and SuiteCommerce Advanced. This change in architecture makes it easier for developers to plug in new customizations and ensure version-to-version stability, and to enable business users to make changes to their site without changing a line of code.

Accordingly, when talking about it from a development point of view, it may be useful to compare it to what was available before. In other words, what were the ‘old’ ways of making customizations to a SuiteCommerce Advanced site, and what problems arose?

From that point, we can then present what the extension framework (which includes the extensibility API, extension manager, new developer tools, and new formal concepts such as extensions and themes) does to solve these problems.

Pre-Extension Framework

Up until Kilimanjaro, customizations to your Kilimanjaro or older web store used a lot of techniques such as extending base classes, overriding files, wrapping methods, and even editing files directly. While we feel that this approach to customization still offers a number of benefits, there were a number of difficulties that they created.

Not only are there concerns around the maintainability of these sorts of customizations (ie from developer to developer, or release to release), there were as an overarching problem. Specifically, it put the responsibility of change into the hands of developers. Changes, small or big, always had to go through a developer. We know from experience that both business users and developers wanted a shift in responsibility. Business users wanted to feel empowered to make changes themselves; and developers want to focus on projects, rather than upkeep.

There was also another problem: at their core, all SCA sites started from the same bundles, but would then fork off as developers customized them. Even sites that ran from the same account, or were maintained by the same developer encountered problems when it came to moving functionality and look-and-feel customizations from site-to-site. A clear example for many developers will be code version migrations — these could often be arduous work for developers, as they would have fit code from one site/version on to another. Developers wanted a better, more reliable way of building customizations and moving them from site-to-site, version-to-version.

When we consider these personas, and then apply some topics to them, we can get a generalized picture of some of the problems:

TopicBusiness UserDeveloper
Look-and-FeelLook-and-feel actions are in the hands of developersLook-and-feel is site-specific; version-specific
CustomizationFunctionality actions are in the hands of developersFunctionality is site-specific; version-specific
Code MigrationNew release migration is a manual, developer-only processCode is modularized, but not easily distributable

These problems are obviously all related. For example, while a business user may be frustrated that they cannot implement a design change by themself, a developer might equally be annoyed that they have to spend their time changing a font color. There are also plenty of other areas where both business user and developer alike suffer some sort of frustration.

Furthermore, for smaller companies with limited resources, these issues are often amplified. If you have no in-house developer, then approaching a third-party to make changes you feel you should be able to make yourself can be prohibitive. And what happens when a new release of SuiteCommerce is released, and you want it? A migration can be time-consuming and expensive.

With the Extension Framework

We recognize the above problems, so this is where SuiteCommerce and the commerce extension framework come in.

While SuiteCommerce Advanced runs from an unmanaged bundle, allowing changes, SuiteCommerce (sometimes referred to as SuiteCommerce Standard) runs from a managed bundle. This means two things: you cannot modify the source code yourself, but you are always running the latest code as we will update your site automatically.

But how you customize the site without modifying the source? The extension framework allows new functionality to be introduced without relying necessarily on the customization methods of yore. There are three key elements to it:

  1. Extensibility API — a stable, code-level API that offers access to key parts of a webstore via standardized objects and methods that remains stable across different sites and different versions
  2. Extensions — packaged-up modules of code that plug in to a site after being ‘activated’
  3. Themes — packaged-up templates and Sass that cover an entire site and can be used to change a site’s look-and-feel that can be swapped out wholesale

So, what do these three things mean? What can we expect to get out of them? Well, from a developer point of view, it means that you should now focus your efforts on creating themes and extensions — formalized packages of look-and-feel and functionality augmentations. These packages can be easily versioned, distributed, and activated across different sites and different versions of sites.

In terms of the redistribution of power between business users and developers, it means that after developers have worked on and then shipped these packages, sites business users are free to activate them on their site if they wish — they can then customize and configure them (if applicable), roll back to a previous version, and deactivate it entirely on their terms.

To summarize the changes that affect SuiteCommerce sites:

CustomizationsMixed with core codeLayered on top of core code
Version UpgradeManualAutomatic update (SuiteCommerce sites only)
Code ReuseManual code copy and maintenanceBundled as an extension
Adding New CustomizationsDownload existing (proprietary) codebase, code customization, and deployPull down extension and theme, code customization, then version, deploy, and activate
Version DependencySubject to change every releaseBackwards-compatible

And what this all means is we:

  1. Get closer to the software as a service (SaaS) model
  2. Minimize the effort of keeping a site up to date
  3. Ensure customizations keep working after a new release
  4. Enable the easy implementation of new features via extensions

A key thing to keep in mind is that regardless of whether you use SuiteCommerce or SuiteCommerce Advanced, the mechanisms and features of the extension framework are available to both products. The crucial difference is that with SCA, you are able to modify the source code — of course, we would still recommend that you use the framework (or at least the API) wherever possible though.

If you are going to 'edit the source' of SCA, as it were, we also still recommend that you follow the traditional way of not editing the source directly, and instead continue keeping your customizations in a separate parent folder, extending, wrapping and overriding as necessary.

Extensions and Themes Overview

OK, so now let's take a look at what extensions and themes actually are.

Extensions are micro-packages of modular SuiteCommerce code. They are bundles, in the NetSuite sense, and add new functionality to a site. They share the benefits that bundles typically have:

  • Easy sharing between production and sandbox accounts
  • Easy sharing to other accounts
  • Can be made publicly available, shared, or private
  • Can be set to 'managed', allowing updates to be pushed by the authors
  • Activated on a site through the extensions management page

Themes are similar but different. They modify how the site looks, rather than behaves, and are:

  • A sub-type of extension
  • Control how a site looks, and what customizations a business user can make to their site's appearance via the theme customizer
  • Typically branched from a 'base theme'

Because of this division of labor — where extensions handle functionality and themes handle appearance — we decided to make the difference formal.

Crucially, you should know that we do not allow SuiteScript, JavaScript and configuration files in themes. However, templates, Sass, fonts and images are allowed in both.

Themes can also come in different flavors called skins. So, for example, while you may like a particular theme lays things out, you may wish to have a particular color scheme: with skins, you can have seasonal presets so that things are familiar but different depending on how you want to brand things. Keep things roughly the same but adjust colors and fonts for fall, winter, spring and summer, for example. Check out our documentation on skins for more information.

Extensibility API

So, one of the key benefits of this paradigm shift is a high level of confidence in extension code continuing to work after an upgrade to the core code. It is the extensibility API that provides that assurance. But how?

In short, it is a logical layer between the internal parts of the code and your code. It's a JavaScript API that is available throughout your site — although some components of it are contextual to the current area (eg the checkout).

In the past, if you wanted to a child view, then we'd tell you to find the view that you want, extend its prototype, wrap its initialize, convert it to a composite view, then add a childViews function, and then call your view there. Now, you can avoid most of that — you just find the component for the part of the site you want to change, and add a child view to that. You don't have to worry about what might happen if we change a name in a release — your code will still work!

The API will keep growing in each and every release. But know that this growth will be sideways, in the sense that we be adding in new methods, and fixes will happen behind the scenes. We want this to be the foundation for customization on SuiteCommerce sites, and we want that foundation to be stable.


Components are the classes from which the extensibility API draws its power. It's a relatively new concept, which adds a new layer of abstraction.

The idea is that instead of going through the source code and finding idiosyncratic solutions to typical problems, you rely on a number of a ready-made classes and methods that we provide. In other words, where you previously had to find a particular object to extend, or a function to wrap, now you can rely on simple, stable methods.

They're somewhere between modules and applications, and can be shared between applications. Some operate globally throughout the site, while others have a specific context. For example, we have a component for the product details page, which is only available on product detail pages. The PDP component can be used, for example, to pull stock information or select matrix options (without the shopper having to click them); it can also be used to listen for specific events, for example after an option has been selected, or before a quantity change occurs.

Components typically have two important kinds of features:

  1. Methods — standardized getters and setters that you can call that simplify fetching contextual data or implementing actions (such as adding to cart, getting the current user’s name, adding a new module to the checkout, etc)
  2. Cancelable Events — new kinds of events that fire before specific contextual actions that allow you to interrupt them from happening (eg performing an additional validation step when a specific promotion code has been added)

The events also let you bind callbacks to after they have completed.

Here are some examples of components:

  • Product details page (PDP)
  • Product list page (PLP)
  • Cart — frontend
  • Cart — backend
  • Checkout
  • Environment
  • CMS
  • Layout

If you've coded a custom content type (CCT) before, then you'll already be familiar with the CMS component as we have to use its registerCustomContent method in its entry point file. The principle for other components is the same.

Take a look at this very simple example: let's say we really want to automatically increase the quantity of the item on a PDP to 10 after the view's content has been rendered — how would we do that? If you had to write that code without using the extensibility API, would you even know how? Would you be sure it was the best way to do it? Would you be sure that it would continue to work on different sites, running different versions of code?

With the extensibility API, it's this simple:

var PDP = Application.getComponent('PDP');
PDP.on('afterShowContent', function ()

We're using two separate two methods: we're setting up an event listener for when showContent has finished, and then running a method for increase the quantity. This'll work on any site running at least this version of the API (at the time of writing), and will continue to work in the future.

Keep in mind that the general idea for components and the extensibility API is for us, NetSuite, to worry about the guts of making technical changes to your site, and then for us to provide you with an easy-to-use toolkit, so you can make the changes you want.

The behavior of the methods you see today probably won't change (or, at least, not drastically — we might add new parameters to existing methods, for example). Instead, the idea is grow their power sideways so that we will eventually encompass all conceivable areas of customization for all areas of the site. In the meantime, you can certainly sit down and get to work for areas of the site we already cover, with the methods and events we already provide.

For a full list of available components, see our frontend extensibility API documentation. Keep in mind that there’s also an extensibility API for the backend, and for SCIS too.

Differences in Source Code and Development

One of the questions you probably have right now is, if there's a new way to add in customizations, does this mean that it will be a different experience to write them? The answer is: yes. I think there are five key differences:

  1. Directory structure and local development with new Gulp commands
  2. Manifests instead of package and distro files
  3. Versioning and activation
  4. New helpers to manage path to assets
  5. Reliance on standardized components and classes, rather than extending source code classes

Source Code

When you get your hands on SuiteCommerce code for the first time, the first thing you may notice is how it is so different from previous versions of SuiteCommerce Advanced code. The core code for SuiteCommerce Advanced Aconcagua contains only the Configuration, JavaScript and SuiteScript files; comparatively, the core code for SuiteCommerce... is not available.

When you develop on SuiteCommerce, you must use either the theme developer tools or the extension developer tools. Both are similar in the sense that they create a microcosmic workspace for you to work. Each one contains just what you need to work on that theme or extension, and nothing else.

If you're developing on SuiteCommerce Advanced, this means that you are potentially working with three different developer tools. Note that these are all kept separate, including the commands. For example, if you are in the context of the SuiteCommerce Advanced developer tools, Gulp commands for themes and extensions won't work!

Because of this small-slice approach, you don't have to deal with package and distro files. Instead, we have manifest files. These provide the indexes required for the compilers to understand where the files are meant to go. They also determine the metadata (name, description, version, etc) that is used in the extension manager.

One important thing to note with manifest files is that they almost entirely automatically generated by Gulp — the only time you need to manually intervene is when you want to add Sass entry points for any newly introduced Sass entry points. You can manually control the manifest but note that it will be overridden on deploy unless you supply a flag on deploy saying not to. For example, let's say you have included a new image asset in your theme, it will automatically be added to the manifest and included with the deploy; however, if after generation, you remember you don't want to include it, you can delete its entry and then specify that you don't want the manifest to be regenerated.

I'll mention the command for this in a moment, but let's look at the development flow in general and as a whole first.

Theme Development Flow

OK, so once you've got the source code — now what?

A flow chart illustrating the steps involved in developing a theme

Before you can begin, you need to get the theme developer tools and install them.

The development process for a new theme should start with an existing theme. We have included a SuiteCommerce base theme, which is designed to work out of the box as well as being an excellent example of best practices. It's available as a bundle, which you install when you prepare an instance for SuiteCommerce, and can then be fetched for use within your development tools.

From there, you can customize the existing theme or use it as a basis for a new theme. If you want to create a new theme, or simply create a new version of the theme, you'll need to update the metadata in the manifest file. In either case, you can do your normal theming work: modify templates, styles and asset files — note that you cannot include any JavaScript, SuiteScript or configuration files in your themes. If you want to use these types of files as part of your site's look and feel then you'll need to create an extension and store them there.

While working, you can use your local server to preview the changes prior to deploy, just like you would with normal extension or SCA development.

When you're done, you update your manifest and deploy your changes. It's important to remember that the deploying a theme or extension doesn't automatically apply it to the site, like in SCA development; instead, you will need to activate it on your site.

For theme development, note that we have new Gulp commands. They all begin with gulp theme and have additional flags at the end, such as:

  • gulp theme:fetch
  • gulp theme:deploy
  • gulp theme:local

In addition to these, some of the commands have additional flags that you can attach them. For example, the aforementioned command to prevent a regeneration of a theme's manifest file is gulp theme:deploy --preserve-manifest — note that you can use with the local keyword too.

See our documentation on Gulp Command Reference for Themes and Extensions for a complete list.

Extension Development Flow

The development flow for extensions is largely similar, but note the differences.

A flow chart illustrating the steps involved in developing an extension

You still need to fetch the current theme, so that you can use this when you start a local server on which to test your extension.

From there you can start work on a new extension, or fetch an existing one and continue working on that. If you do create a new one, you can use a new Gulp command to automate it. When you run gulp extension:create you will be asked a series of questions about your proposed module — these range from basic metadata questions to questions about the types of files you're going to include. Based on that information, a number of dummy files (such as an entry point file, a view, etc) which are properly namespaced and correctly set up with dependencies. You don't have to run it if you don't want, but you may find it much easier to get started with.

From there you do your work, spin up a local server, and, when you're finished, deploy and activate. Simple.

Check out the documentation mentioned above for the Gulp commands associated with extension development — they're different but similar.


When you deploy your code to NetSuite, the system will check to see what version number is included in the manifest. If a version in NetSuite already exists with that version, it will overwrite any files in NetSuite that's already exist for that version. If it's a new version, NetSuite will go through the steps of creating new records for your theme or extension. This is important to keep in mind.

If you're working on a development version of your theme or extension, then you should feel free to overwrite the 'development version' number you've given it. However, once you're happy with a version and have 'released' it, then you should be wary of overwriting an existing version.

In other words, we strongly recommend that you employ versioning discipline to prevent old, stable versions of your work from being summarily replaced. For example, we recommend using a version control system (eg Git) for your work, in addition to the versioning offered by NetSuite.

Referencing Assets Across Versions

One issue that versioning introduces is to do with asset files, ie, fonts and images. After all, if they are updated in a version and you want to roll back to an older version, won't the old theme or extension use the new asset files?

The answer is no: when a new version is created, its files are stored separately from all other versions. But, this begs the question: when working on template and Sass files, how you do reference the asset of the currently activated version? We have implemented special helpers for Sass and Handlebars. Note that the Handlebars helpers can also be used in your JavaScript, so long as you first add HandlebarsExtras as a dependency.

Let's take a fantastical example: let's say you want to set an image as the background of your body tag. But, this image could change with each release — how can you mark up your Sass file so that the correct URL path is always generated?

/* Example Sass */
body {
   background-image: url(getThemeAssetsPath('img/flowers.jpg'));

/* Example after evaluation */
body {
    background-image: url(

/* Example with unevaluated placeholders */
body {
    background-image: url(<domain>/c.<company ID>/<SSP application>/extensions/<vendor>/<theme name>/<version>/img/<file name>)

In other words, getThemeAssetsPath and its siblings do the hard work of resolving the correct URL paths. It still uses the traditional getAbsoluteUrl, but it does some work before hand to ensure the correct extension (themes are extensions!) and version are included.


OK, let's talk about something I've mentioned a few times now: activation.

After your theme or extension has been deployed, it is not automatically applied to your site: it must be activated. This is true even if you're overwriting an existing version of code. This is one of the differences you will notice when working on extensions and themes; in this sense, you could consider these environments to be microcosmic.

When you've finished writing and testing your extension locally, your new code must be muxed with the SuiteCommerce base code — and any other theme or extension code — to produce to final compiled output. This process is called activation, and it takes place in the Extension Management page (Setup > SuiteCommerce Advanced > Extension Management).

A screenshot of the landing page of the extension manager page. Each row is a site, which has different themes and extensions activated on them, plus a status (eg, if there are activations in progress)

After selecting what site you want to change, you're asked to select a theme and extensions to activate. Note that previously installed versions of an extension are saved and can be activated if you want to roll back.

Metadata about each extension is provided — name, description, version and provider — to aid you to make a decision. When you've made your choices, activation runs and recombination begins, which will output your site's final code.

Also note that while I have used the word 'site', you actually activate themes and extensions on a per domain basis. What this means is that if you operate multiple SSP applications for development, or otherwise have different domains for different versions of your site, activation on each occurs separately. (I will, however, continue to use the word 'site' in this post.)

So. With that in mind, how do all the bits connect together?

A diagram showing a locked container around the SuiteCommerce core and extensibility layer, but allowing connections to themes and extension code through the extension manager

Unless you are developing on SuiteCommerce Advanced, the core SuiteCommerce source code is locked down. Any code-level customization you wish to make must plug into the extension manager, and, for extensions, this means talking to the extensibility API. If you are developing on SCA, you can (and should) use themes and extensions, but you do not have to.

But, yeah, for SuiteCommerce developers, the core SuiteCommerce code (and the extensibility API it provides) is locked and managed by us. If you want to communicate to it — ie add new functionality or change how it looks — then you add in a theme and extensions. You can activate as many extensions to your site as you wish, but only one theme.

Best Practices

Using best practices will ensure that your extensions take full advantage of the benefits of the framework. It means that as time goes on, your extensions will require less work to maintain and scale more easily. Remember, the key concepts here are to do with sustainability and upgradeability — using the extension framework to its fullest may mean having to re-learn the best ways of doing things.

Dependency Management

First, avoid relying on activation order.

If you have multiple extensions and they depend on each other, they should not require one extension to be muxed into the code first.

Second, when you need to access the SuiteCommerce core, use the extensibility layer exclusively. When writing in the isolated extensions developer environment, it may be tempting to open up your other folder, which contains the SCA core code, and find particular functions to wrap or classes to extend — resist this temptation.

When an upgrade happens, you may find that a name has changed, or that module no longer exists, or is in the process of being deprecated. We will update the extensibility API so that the methods you rely on can continue to be relied upon, but the inner parts of them may change.

Third, when interacting with a theme, it is best to depend on the templates, Sass variables, and classes that are bundled with SuiteCommerce. Again, think about what will happen when a site is upgraded: we (NetSuite) will test our work with the base theme to ensure it works, and we will certainly include updates to the base theme. You should, therefore, try to rely on the base theme as much as possible.

Finally, when working with other extensions, the answer depends on whether you own the extension or don't. So, if the extension is your own then we encourage you to consider making your own interface — perhaps your own component! — and then work with that. This allows you to apply the same principles we use for our code. Create a controlled, stable API for it that won't change, and then talk to it through that. That way, if you need to change the underlying code, you can minimize the impact it will have on the extensions that depend on it.

If you don't own it, try to attach as little as possible to it. Avoid unnecessary dependencies. You could create an adapter — but this is a pretty advanced software design topic that we don't cover, so you'll need to do some independent research on it yourself.

A complex diagram showing the interactions between various aspects of a site, and the appropriate way of smoothly connecting between them

The above images illustrates these different approaches:

  1. If you need to customize the behavior of the site, use an extension and, if possible, the extensibility layer
  2. New templates and Sass can be added by an extension, but all core template and styles now live in your site’s theme
  3. If you need to modify the behavior of extension that you own, modify the original extension to provide an interface for your new extension
  4. If you don’t own the extension you want to modify, explore the concept of an adapter

Scope of Extensions

When developing large customizations, the question arises as to whether you should put everything in one extension, or whether you should split them up into smaller ones. The answer is: it depends.

This is a question you'll have to answer for each project. We would counsel that you avoid the two extremes: avoid putting everything into one huge extension, and avoid putting everything into piecemeal ones. It's undesirable to maintain one mammoth extension; it's undesirable to maintain twenty small ones.

When deciding, consider three core principles:

  1. Reusability — could this parcel of functionality be used by something else? Perhaps it should be split off from the rest.
  2. Independence — if I extract this functionality, will it work standalone from the rest?
  3. Maintainability — what makes this code easier to maintain? Keeping it with its cohorts or separating it out?

Extension Code Structure

In general, follow similar coding standards that you would for SCA. Realistically, this means don't feel confined to a one-module/one-extension model: feel free to split up your functionality across multiple modules if it helps. Similarly, doing so consider the advice we just gave about the scope of extensions — is the new module you're creating reusable, independent and easy to maintain?

Templates and Sass

Templates and Sass that are specific to an extension should always go with that extension: do not put them into your theme.

Remember that a site's theme will contain a number of Sass variables (eg for colors) and you are free to use them in your extension's Sass files. This is why you must fetch the site's theme when developing, and part of the reason why we recombine files during the activation process: everything is joined up, so make use of all the bits!

However, the question arises about what to do when templates are shared between extensions. There are two options: extract part of the template into a child view to abstract that part, or voluntarily keep it in the theme. The latter may be preferable as its better for multiple extensions to depend on a theme rather than than a theme on an extension, or extensions between themselves. Remember, your theme can always be forked — taken off the vendor's upgrade path — and then tailored to fit your site's needs. Be wary, however, as this can cause maintenance headaches later on.

It's important to think long-term, for example:

  • If you feel a specific area of a page might have a child view in the future, you can always add in a placeholder now and use it later on, as this will avoid you having to edit the theme later
  • If you're developing something for the market, it's probably wise to try to keep your extension as contained as possible

Keep in mind things like what happens when a site is upgraded to a newer version, there's an upgrade to theme, or the extension is ported to another site with a whole different setup.

Handling New Releases

One thing to make clear: upgrades don't take effect until you activate them. However, be aware that if you're developing on a SuiteCommerce site then know that any activation will trigger a recombination with the latest core SuiteCommerce code.

Generally speaking, take advantage of test domains. You have access to a release preview account, plus you're free to setup your own test domains. These things should be relatively easy to test without it affecting your live site.

When a core NetSuite release is made available, it should have a minimal impact on your site, so testing in release preview should be fine.

For SuiteCommerce release, it's probably a good idea to test things on a test domain on the same account.

Finally, if you're using a theme or extension then, again, try it out on a test domain. Unmanaged bundles can be manually updated at a time to suit you, so take advantage of that.

Code Versioning

We talked about this a bit already, so let's reiterate.

We always recommend versioning your code in a version control system outside of NetSuite, such as Git. A basic implementation is easy to get started with.

For more advanced users, consider what strategy you want for internal vs deployed code; ie, the code you're currently working on vs what is actually published. You could have a stable (master) branch in your VCS and, after each merge, publish your extension as a new version. Thus, this creates a map between merges and NetSuite versioning.

There's also a wider strategy to consider: what are the purposes of the extensions of your extensions? Do you want to have one big repository for all of your site-specific extensions and themes? Maybe you want to have individual repositories for each extension and theme? Maybe you even want some sort of hybrid, where reusable extensions are in one and site-specific ones are all grouped up together. We can't answer these questions for you — you will need to consider the scope of your work, and what makes most sense to you.

Migration From SCA

Perhaps the biggest question a lot of you will face: should I take my current site customizations and build them out into themes and extensions? In short, yes.

If you compare the source code of Kilimanjaro to Aconcagua, you will see that we've moved all of the templates and Sass into the base theme. You can do the same: follow the steps for creating a new theme, and then copy and paste each folder into your new theme workspace. Keep in mind, however, that there were likely some changes, additions and deletions in the Aconcagua release. You may want to do a full diff of the template and Sass files to see if you missed anything.

If you're interested in taking advantage of the new theme customizer in the site management tools, then you'll need to do some work to make it ready. We have developer docs on how to do this and it may well feature as a topic in future blog posts. It's an important feature of our push for business user independence, so we encourage taking it up.

When it comes to JavaScript that you used for look-and-feel and user experience (eg animations), the only solution is to add these to an extension. You could consider refactoring them to be CSS only (HTML5 and CSS3 is pretty powerful now, you know) or perhaps removing them entirely. However, there's nothing wrong with writing a proper UX extension, containing all of the site-specific things you need to make your site beautiful.

As for custom functionality, you may find that refactoring to be particularly hard work. In any case, be systematic and try to identify areas that could make use of the extensibility API. If you have customizations that don't yet cover areas supported by a component, consider keeping them separate from the rest of your extensions. For example, the account application does not currently have a component, but it (probably) will later on. If you have customizations here, try to keep them isolated for now.

Remember that anything that is already completely separate — for example if you have custom pages or features — can (and probably should) be their own extension. It can still have its own router, model, views, etc. Just keep in mind that you may be able to take advantage of some components along the way too.

Final Thoughts

While we covered a lot of best practices in this article, the next step for you might be to build your own extension or to read more; for example, see our article on how to Build Sustainable and Stable Extensions.