Marcos Mansilla

NetSuite SPA Guide: JSX, UIF, and What’s New in 2025.1

Single Page Applications (SPAs) have become the go-to approach for building fast, responsive web interfaces. Instead of loading a new HTML page every time a user clicks something, SPAs load everything up front and then update the page dynamically. This gives users a smoother, app-like experience in the browser.

At a high level, SPAs work by handling routing and rendering on the client side. After the initial load, all page interactions are managed with JavaScript. When a user navigates or performs an action, the app requests only the data it needs from the server, usually through APIs, and updates just part of the screen. That means there will be fewer full-page reloads, faster transitions, and a more fluid user experience.

NetSuite SPA Guide

Table of Contents

What’s New in NetSuite 2025.1

With the 2025.1 release, NetSuite ERP introduced support for Single Page Applications (SPAs), a huge step forward in building modern, interactive experiences directly within the NetSuite UI. For developers, the real game changer is the ability to use JSX inside NetSuite. JSX brings a familiar, React-like developer experience to ERP customizations.

The Technology Behind NetSuite ERP SPA

To understand how SPAs work in NetSuite, it helps to know the core technologies involved. Each layer, from SuiteScript to UIF, plays a key role in creating a modern, responsive ERP UI.
 

How to Configure the SPA in NetSuite ERP

If you’re ready to build your first Single Page Application in NetSuite, here’s a step-by-step walkthrough, from project setup to deployment.

Step 1: Prerequisites

  • NetSuite release 2025.1 or higher
  • SuiteCloud Development Framework (SDF) enabled for the target account (Setup → Company → Enable Features → SuiteCloud).
  • Use SuiteScript 2.1 (SPAs require 2.1).
  • Permissions for SPA deployment.

Single Page Applications for NetSuite ERP are built inside an SDF SuiteApp project, use SuiteScript 2.1, require two script types (SPA server and client), and need a build step to transpile/convert JSX/ESM into the AMD/RequireJS modules NetSuite expects.

Step 2: Create an SDF Project

				
					npm i -g @oracle/suitecloud-cli
suitecloud project:create --type SUITEAPP --projectid com.myorg.myspa --projectname "My SPA SuiteApp" --publisherid com.myorg --projectversion 1.0.0
				
			

Step 3: Add the SPA folder + object XML (the SDF object that registers the SPA)

Inside your project put the SPA sources under:

				
					src/SuiteApps/<publisherid>/<spa-folder>/
  ├─ SpaClient.jsx    (or .js produced after build)
  ├─ SpaServer.js
  └─ assets/...
				
			

Then add a singlepageapp object XML in src/Objects, e.g. src/Objects/custspa_appdashboard.xml:

				
					<singlepageapp scriptid="custspa_appdashboard">
  <name>My SPA Dashboard</name>
  <description>SPA example for ERP</description>
  <url>app-dashboard</url>                      <!-- path after /spa-app/<appID>/ --><folder>[/SuiteApps/com.myorg.myspa/app-dashboard/]</folder>
  <clientscriptfile>[/SuiteApps/com.myorg.myspa/app-dashboard/SpaClient.js]</clientscriptfile>
  <serverscriptfile>[/SuiteApps/com.myorg.myspa/app-dashboard/SpaServer.js]</serverscriptfile>
  <assetsfolder>[/SuiteApps/com.myorg.myspa/app-dashboard/assets/]</assetsfolder>
  <audienceallroles>T</audienceallroles>
</singlepageapp>
				
			

That XML pattern (tag <singlepageapp …>) is the official way to register the SPA URL, folder and the client/server script files.

Step 4: Implement the SPA server script (entry point that runs before client code)

The server script uses @NApiVersion 2.1 and @NScriptType SpaServerScript.
It must export initializeSpa(context); the context object can add stylesheets and do checks (audience, preliminary data, error/denial, etc.).
Example SpaServer.js:

				
					/**
 * @NApiVersion 2.1
 * @NScriptType SpaServerScript
 */
import runtime from 'N/runtime';
import log from 'N/log';

export const initializeSpa = (context) => {
  const user = runtime.getCurrentUser();
  log.debug({ title: 'SPA init', details: `User ${user.id}` });

  // optionally add an assets CSS file (path is relative to the assets folder)
  context.addStyleSheet({ relativePath: '/css/spa.css' });

  // throw a string or Error to block loading if needed// if (user.id !== SOME_ID) throw 'Unauthorized user';return;
};
				
			

Step 5: Implement the SPA client script and root JSX component

  • Client script must export run(context) — NetSuite calls it when the NetSuite center finishes loading.
  • The context API exposes context.setLayout(…) and context.setContent(<RootComponent />)setContent() accepts a NetSuite UIF component (your root component can be written in JSX using the UIF components). Example below.

SpaClient.jsx (source — transpile this before deploy; see next step):

				
					
// SpaClient.jsx  (source in JSX/TSX)import HelloWorld from './HelloWorld.jsx';

export const run = (context) => {
  // layout types: 'application' fills the viewport; see docs
  context.setLayout('application');
  // render the UIF root component (JSX)
  context.setContent(<HelloWorld />);
  // optionally return a promise if asynchronous work is needed
};
				
			

HelloWorld.jsx (root component using UIF components — imports shown per UIF catalog):

				
					import { ContentPanel, Heading, Button } from '@uif-js/component';

export default function HelloWorld() {
  return (
    <ContentPanel>
      <Heading level={1}>My SPA (JSX)</Heading>
      <p>Welcome to the SPA running inside NetSuite ERP.</p>
      <Button onClick={() => alert('Clicked!')}>Click me</Button>
    </ContentPanel>
  );
}
				
			

Step 6: Build / transpile / convert (mandatory)

Important: NetSuite expects AMD/RequireJS modules and UIF ESM components; your SPA sources (JSX/TSX + ESM import) must be transpiled and converted before deploying. The sample SPA SuiteApps in Oracle’s GitHub include a gulpfile that performs the build/bundle/convert steps (transpile JSX → JS, convert import/export to NetSuite module format). You can also use your own toolchain (webpack/rollup + Babel) as long as output lands in the Single Page Application folder as plain JS the SDF project references. Oracle Documentation

Example high-level build flow (in package.json):

				
					"scripts": {"build": "gulp build",      // or: webpack --config webpack.spa.config.js"validate": "suitecloud project:validate","deploy": "suitecloud project:deploy"}
				
			

The key is the build output must put the compiled SpaClient.js and SpaServer.js (and assets) into the SPA folder referenced by your singlepageapp XML.

Step 7: Manifest / feature dependency

Add the Server Side Scripting feature to your manifest so SDF includes required features:

				
					<dependencies>
  <features>
    <feature required="true">SERVERSIDESCRIPTING</feature>
  </features>
</dependencies>
				
			

The docs explicitly recommend adding SERVERSIDESCRIPTING to manifest.xml for SPA SuiteApps. Oracle Documentation

Step 8: Validate & deploy with SuiteCloud CLI

  • Validate project locally:
				
					suitecloud project:validate        # flags available e.g. --applyinstallprefs
				
			
  • Deploy:
				
					suitecloud project:deploy
				
			

SDF deploy will package the project (per deploy.xml) and upload the referenced objects/files to the target account. Use a sandbox/account you control when testing.

Step 9: Test in NetSuite

Access the SPA URL defined in the SPA object (/spa-app/<ApplicationID>/<url>). The Single Page Application server script runs first (initializeSpa), then the client script loads and run(context) is called; the UI shows a loading icon until run resolves. Confirm audiences/roles in the SPA object XML so only intended users see it.

Tips, Gotchas & Best Practices for NetSuite Single Page Applications

  • Use the Oracle sample SPA SuiteApps as a starting template. They include gulp build steps and the proper folder layout.
  • Remember: you cannot run the Single Page Application fully locally without deploying (local dev is limited) — samples and community threads mention this constraint. Plan quick iterative deploys to a sandbox.
  • Keep server-heavy work in the SPA server script or SuiteScript services; keep rendering and event logic in the client/JSX. Use context.setContent() to mount your UIF root component.
  • Componentize your UI: Create reusable JSX components for buttons, tables, filters.
  • Keep logic separate: Use SuiteScript services for data calls, keep JSX focused on rendering.
  • Leverage UIF components: Don’t reinvent inputs, grids, or layouts; extend what’s available.
  • Test with multiple roles: JSX code runs client-side, ensure role permissions are set properly.

Final Thoughts on NetSuite SPAs and JSX

NetSuite’s SPA framework for ERP finally modernizes ERP customization, bringing developers closer to the experience they know from React, Vue, and other modern frameworks. With JSX support, you can now write clean, component-based UIs directly in NetSuite, backed by SuiteScript and UIF.
 
If you’ve been frustrated with the limitations of Suitelets or SuiteScript-based UIs, SPAs + JSX are your ticket to building faster, modern, and maintainable interfaces inside NetSuite ERP.

FAQ

Still have questions about how Single Page Applications fit into NetSuite development? Here are some quick answers to common questions developers ask.
A SPA is a web app that loads a single HTML page and dynamically updates content without reloading the whole page. This approach creates faster, smoother user experiences compared to traditional multi-page apps.

NetSuite 2025 introduces support for JSX within its SPA framework. While it’s not React, the syntax and approach are similar.

Yes, SPAs can interact with NetSuite data using SuiteScript APIs, making them great for building custom UI flows.

Yes. Since SPAs only load data as needed and avoid full page reloads, they provide faster navigation and a smoother experience.

SPAs are supported in NetSuite 2025.1 and above. Users must have SDF enabled and appropriate permissions to deploy SPA scripts.

Picture of Marcos Mansilla

Marcos Mansilla

Engineering Manager at UnlockCommerce, with a robust background in software development and team leadership. Marcos specializes in guiding engineering teams to deliver high-quality, scalable, and efficient solutions tailored to meet client needs. His expertise in SuiteCommerce and Shopify and deep understanding of NetSuite and eCommerce systems ensure seamless execution and innovative results for our clients. Marcos is dedicated to fostering collaboration and driving excellence across all technical initiatives.

Share this post

You may also like