In plain English
NetSuite’s original way of scripting — SuiteScript 1.0, full of nlapi and nlobj functions — is on its way out. The modern way, SuiteScript 2.x (with 2.1 adding async/await and other modern JavaScript), is faster to write, easier to maintain, and the only version still getting new features. Migrating means rewriting your old scripts in the new style — and because you can’t call 1.0 from 2.x, it’s a genuine rewrite, not a quick wrapper. Done in the right order, it’s very manageable.
Same platform, a very different style of code. The migration moves every script from the left column to the right.
Why bother migrating?
Three reasons. First, 1.0 is deprecated — no new features land there, and one day it stops working. Second, 2.1 code is simply nicer to work with: modular, modern JavaScript with a fraction of the boilerplate, so it’s cheaper to maintain and onboard new developers onto. Third, the newest NetSuite capabilities (and the lighter, faster APIs) are 2.x only. So it’s really a question of when, not if.
The migration, in five steps
You don’t rewrite everything overnight. A good migration is a sequence: understand what you have, translate it, rebuild it cleanly, modernize it, then roll it out carefully.
Audit → map the APIs → rebuild as modules → modernize the syntax & error handling → roll out sandbox-first. The expert version has the code for each phase.
What changes, in plain English
The expert version has the side-by-side code. The short story is seven shifts:
Modular architecture
Code is split into small modules loaded with define()/require, not one giant procedural file.
The API map
Every nlapi/nlobj call has a 2.x equivalent (or a documented workaround). It’s your migration dictionary.
No mixing the two
You can’t call 1.0 APIs from 2.x. It’s a real rewrite, not a wrapper around the old code.
Modern JavaScript
2.1 brings promises, async/await, destructuring and optional chaining — far less boilerplate.
Real error handling
N/error plus try/catch replaces silent failures and the old “return false” habit.
JSDoc tags
Every 2.x script needs @NApiVersion and @NScriptType tags — without them it won’t deploy.
Sandbox-first rollout
Migrate script by script, test in Sandbox, run old and new side by side, then cut over with a rollback plan.
What to remember
- 1.0 is on its way out — new features only land in 2.x, so migration is a question of when, not if.
- You can’t call 1.0 from 2.x — plan a rewrite, guided by NetSuite’s official API Map.
- Don’t big-bang it — migrate script by script, Sandbox-first, with a rollback plan.
Quick summary: SuiteScript 1.0 still runs in NetSuite, but new development should be on SuiteScript 2.1 — the GraalVM-based runtime that supports modern JavaScript (ES2019+), async/await, and the modular Records and Search APIs. This guide walks through how we migrate production NetSuite codebases from 1.0 to 2.1 without breaking operations: auditing scripts, restructuring with AMD modules, applying async patterns safely, hardening error handling, and rolling out behind feature flags.
Over the last eight years, our team has migrated SuiteScript codebases for ecommerce, wholesale, and B2B retail businesses across the US, UK, CA, Australia, and New Zealand. The patterns below are the ones that consistently work in production — not the textbook version of "rewrite everything in a weekend."
Why migrate from SuiteScript 1.0 to 2.1?
Beyond the obvious "the legacy API is on its way out" answer, the practical reasons compound quickly:
- Modern JavaScript syntax — Promises,
async/await, destructuring, optional chaining, and AMD modules dramatically reduce boilerplate compared to 1.0's procedural style. - Better governance behavior — 2.1 scripts use governance units more efficiently in many search and record operations, especially when paired with the
N/querymodule. - Improved debugging — The 2.x debugger and the structured
logmodule are meaningfully better thannlapiLogExecution. - GraalVM runtime — SuiteScript 2.1 runs on a GraalVM JavaScript engine that supports ES2019+, which 2.0's older engine did not. (See NetSuite's official 2.x overview.)
- Hireability — Modern engineers do not want to learn a deprecated procedural API. This affects your cost of hiring, onboarding, and retention.
Step 1 — Audit your codebase before writing any 2.1 code
Before writing a single line of 2.1, build an inventory. We typically pull a saved search of all script records and categorize each one by:
- Script type (User Event, Scheduled, Suitelet, Client Script, Map/Reduce, RESTlet, Mass Update, Portlet)
- Last modified date and last execution date
- Lines of code and external dependencies
- Business criticality (P0 / P1 / P2)
- Governance unit consumption per execution (from the script execution log)
You will often find that 60–70% of the codebase has not executed in months. Those go to the bottom of the list — or the archive pile. The remaining 30–40% is where migration ROI lives.
Step 2 — Embrace the AMD module architecture
SuiteScript 2.x is module-based via AMD define(). The biggest mindset shift from 1.0 is treating every script as a composable unit rather than a flat list of functions in the global scope.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/record', 'N/search', './lib/orderUtils'],
(record, search, orderUtils) => {
const afterSubmit = (context) => {
if (context.type !== context.UserEventType.CREATE) return;
const order = context.newRecord;
const tier = orderUtils.classifyOrder(order);
log.audit('Order classified', { id: order.id, tier });
};
return { afterSubmit };
});
Notice how the entry point stays small — heavy logic moves into shared library modules under a /lib/ folder in the file cabinet. This is the pattern that scales as the codebase grows.
Step 3 — Async patterns done right in SuiteScript 2.1
SuiteScript 2.1 introduces .promise() variants on most APIs, plus full async/await support in client scripts, Suitelets, and RESTlets. This is the single biggest quality-of-life upgrade.
"Once you have used await search.lookupFields.promise(...) instead of nesting callbacks three levels deep, you will never want to go back to 1.0."
Two cautions, though. First, not every SuiteScript module supports the promise variant — check NetSuite's per-module documentation before assuming. Second, async does not mean free. You are still accumulating governance units, just on a different timeline. Promise.all across 50 record loads will burn the same units as 50 sequential loads — the script just finishes the calendar time sooner.
Step 4 — Error handling that actually works
One of the most common 1.0-isms we rip out is the empty try/catch that silently swallows errors. In 2.1, lean on the N/error module for typed exceptions:
const err = error.create({
name: 'INVALID_ORDER_STATE',
message: `Order ${id} is not in a fulfillable state`,
notifyOff: false
});
throw err;
This gives you searchable error names in script execution logs and makes debugging production incidents dramatically easier. Pair it with a structured log.error call that includes the record ID, user, and trigger — without that context, production diagnostics on a busy account are guesswork.
Step 5 — Rollout strategy
Never deploy a SuiteScript migration as a big-bang release. Our standard approach has five phases:
- Mirror in sandbox — Deploy old and new versions side-by-side, route real production data through both, log both outputs, compare for drift over a full close cycle.
- Feature-flag the cutover — A simple custom record or script parameter that lets you toggle which version handles each event type or user role.
- Canary on low-volume scenarios first — Migrate the lowest-stakes script type first (a portlet or mass update is safer than a User Event on Sales Order) to validate your patterns before touching critical paths.
- Monitor governance and execution time — Pull script execution logs for the first two weeks post-cutover; new code has new performance characteristics.
- Decommission, do not delete — Inactivate the old script for at least one full close cycle before deleting the file. If anything goes sideways during month-end, you want the old version one click away.
Key takeaways
- Audit before you migrate — most of your 1.0 code probably is not worth touching.
- Treat AMD modules and shared library files as a first-class architectural concern, not an afterthought.
- Use
async/awaitin 2.1 — but governance still applies. - Type your errors with
N/error; never swallow them silently. - Always run old and new in parallel before cutover; never go big-bang on a live account.
If you are staring at a 1.0 codebase and not sure where to start, talk to one of our engineers — we will do a free audit and give you a real migration roadmap, not a sales pitch. You can also browse our other NetSuite engineering articles for related deep-dives.
Frequently asked questions
Is SuiteScript 1.0 still supported by NetSuite?
Yes — SuiteScript 1.0 still runs and is technically supported, but Oracle officially recommends SuiteScript 2.1 for all new development. Continued reliance on 1.0 means you cannot use modern JavaScript, async/await, or the GraalVM-based runtime that powers 2.1.
Can SuiteScript 1.0 and 2.1 run in the same NetSuite account?
Yes. SuiteScript 1.0 and 2.x can co-exist on the same account and even on the same record. They cannot share the same script file, but a 1.0 script can call a 2.x RESTlet — a common bridge pattern during gradual migrations.
How long does a SuiteScript migration usually take?
For a typical mid-sized NetSuite account with 30 to 80 active 1.0 scripts, a phased migration takes 8 to 16 weeks of engineering time. Pure script-by-script rewrites are faster; tightly integrated codebases with shared utility libraries take longer because the library layer must be re-architected first.
What is the difference between SuiteScript 2.0 and 2.1?
SuiteScript 2.0 introduced AMD modules and the modern Records and Search APIs. SuiteScript 2.1 runs on a GraalVM JavaScript engine that supports ES2019+ syntax — let, const, arrow functions, classes, template literals, async/await, optional chaining, and nullish coalescing. Most 2.0 scripts run unchanged in 2.1 with only the @NApiVersion header updated.
Should I migrate every 1.0 script, or only the ones I actively maintain?
Audit first, migrate selectively. In most NetSuite accounts, 60 to 70 percent of legacy scripts have not executed in months. Inactivate or archive those, and prioritize migration for scripts you actively extend, scripts handling business-critical workflows, and scripts that block adopting newer NetSuite features.