If NetSuite’s native records and workflows are the foundation of the platform, SuiteScript is what lets you bend that foundation to fit how your business actually works. SuiteScript is Oracle NetSuite’s JavaScript-based framework for extending and automating the application, and it is organized into distinct script types that each run at a different moment in the system. In this first post of our SuiteScript series we focus on the two script types you will meet earliest and most often: the User Event script and the Client script. We will explain what each one does, show a working code example, and then walk through a real-world scenario that ties them together.
What a SuiteScript Module Actually Is
In SuiteScript 2.1 every script is an AMD-style JavaScript module. You declare which NetSuite API modules you depend on, NetSuite loads them for you, and you return an object whose properties are entry point functions. NetSuite calls those functions automatically at the right time. The two lines that define every script are the @NApiVersion tag, which pins the script to 2.1, and the @NScriptType tag, which tells NetSuite when the script should run. Common API modules you will import include N/record for reading and writing records, N/search for querying data, N/runtime for context and governance information, and N/log for writing to the execution log.
User Event Scripts: Server-Side Business Rules
A User Event script runs on the NetSuite server whenever a record is loaded, saved, or deleted. It exposes three entry points: beforeLoad runs as a record opens, beforeSubmit runs right before a record is written to the database, and afterSubmit runs immediately after the save completes. Because it executes on the server, it fires no matter how the record was changed, whether through the UI, a CSV import, a web service, or another script. That makes it the right place to enforce validation, stamp default values, and trigger downstream actions.
Example: Validating a Sales Order Before It Saves
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/error'], (error) => {
const beforeSubmit = (context) => {
// Only run when a record is created or edited
if (context.type === context.UserEventType.DELETE) return;
const rec = context.newRecord;
const total = rec.getValue({ fieldId: 'total' });
const terms = rec.getValue({ fieldId: 'terms' });
// Orders above 10,000 must have payment terms selected
if (total > 10000 && !terms) {
throw error.create({
name: 'MISSING_TERMS',
message: 'Orders over $10,000 require payment terms.',
notifyOff: false
});
}
};
return { beforeSubmit };
});
Because this logic lives in beforeSubmit, the order is blocked before it ever hits the database. A sales rep saving in the browser sees the error message, and the same rule protects a bulk CSV import that would otherwise slip past a UI-only check.
Client Scripts: Instant Feedback in the Browser
A Client script runs in the user’s browser while a form is open, so it is perfect for interactive behavior that should happen before anyone clicks Save. Its entry points include pageInit when a form loads, fieldChanged when a field value changes, validateField for per-field checks, and saveRecord for a final gate before submission. Client scripts make the interface feel responsive, but they are easy to bypass, so they should complement server-side rules rather than replace them.
/**
* @NApiVersion 2.1
* @NScriptType ClientScript
*/
define([], () => {
const fieldChanged = (context) => {
if (context.fieldId !== 'custbody_discount_pct') return;
const rec = context.currentRecord;
const pct = rec.getValue({ fieldId: 'custbody_discount_pct' });
if (pct > 25) {
alert('Discounts above 25% need manager approval.');
}
};
return { fieldChanged };
});
A Real-World Example: The $12,000 Rush Order
Picture a distributor whose sales team occasionally enters large rush orders without the payment terms the finance team needs. The two scripts above work together to solve this. As the rep builds a $12,000 order in the browser, the Client script watches the discount field and warns them the moment they type 30%, giving instant feedback without a page reload. When they finish and hit Save, the User Event script’s beforeSubmit function checks the order total and terms on the server. The order is over $10,000 and terms are still blank, so NetSuite refuses to save it and shows the finance-approved message. The rep selects Net 30, saves again, and the order goes through. The result is a single business rule enforced in two places: a friendly nudge in the interface and a hard guarantee on the server that no channel can bypass.
Key Takeaways
User Event scripts give you trustworthy, server-side enforcement that runs for every save, edit, and delete regardless of the source. Client scripts give you fast, in-browser interactivity that guides users before they submit. Use them together, keep your governance usage in mind, and always treat the server-side rule as the real gatekeeper. In the next post we will move from event-driven scripts to background processing with Scheduled and Map/Reduce scripts, where SuiteScript handles thousands of records without a user in sight.
Discover more from The NetSuite Pro
Subscribe to get the latest posts sent to your email.
Leave a Reply