Every account I have audited this year has had the same moment. We finish the SuiteScript 1.0 inventory, the list comes back with four scripts on it instead of forty, and somebody in the room exhales and says “oh good, we’re mostly on 2.0 already.”
That is a real result and it is worth being pleased about. It is also not the end of the conversation, and the reason is sitting in the same 2026.2 release notes everyone read the 1.0 part of.
What is actually true right now
Let me be precise about this, because there is a lot of loose talk going around and the difference matters when you are asking for budget.
SuiteScript 1.0 has a hard date. It is removed at 2027.1, along with NLAuth. That is not a recommendation, it is a removal, and we have covered it at length across this series.
SuiteScript 2.0 is named in the same deprecation notice, with no published end date. Oracle’s messaging is that 2.1 is the version you should be on and that older versions will stop working in a future release. Which release, they have not said.
So if someone tells you 2.0 dies at 2027.1, they are guessing, and you should not build a project plan on it. But if someone tells you 2.0 is fine and unaffected, they have not read the notice. The honest position is the uncomfortable middle one: there is no deadline yet, the direction is unambiguous, and the work is small enough that waiting for the deadline is the expensive choice.
That last part is the actual point of this post. Going from 2.0 to 2.1 is nothing like going from 1.0 to 2.x. It is not a rewrite. In most cases it is one line.
The one-line version, and why “usually” is doing a lot of work
Here is the entire migration for a well-behaved script:
/**
* @NApiVersion 2.0 <-- change this
* @NScriptType UserEventScript
*/
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
That is it. No module changes, no API changes, no new entry points. Every N/ module you are using works the same way. Most scripts flip over and behave identically.
The catch is that 2.1 runs on a different engine, and that engine is stricter and more standards-correct than the 2.0 one. Code that was quietly wrong in 2.0 does not stay quietly wrong. It throws.
This is good news in the long run and annoying news on a Tuesday afternoon. Here is what actually surfaces.
The differences that will bite you
Strict mode, and reassigning a const
This is the number one thing you will hit. In 2.0 you could get away with things the language says you should not do. In 2.1 you cannot.
The concrete case that shows up most: reassigning a variable declared with const. In 2.0 this was tolerated. In 2.1 it throws a TypeError, and it throws at runtime, in production, on the line that runs once a month.
const total = 0;
lines.forEach((line) => {
total = total + line.amount; // fine in 2.0, throws in 2.1
});
The fix is obviously let, and the reason people wrote it this way is that they picked up the habit of declaring everything const from a style guide and never noticed the engine was not enforcing it.
Reserved words used as identifiers
If you have a variable or property literally named something the language reserves, 2.0 shrugged and 2.1 does not. This turns up in older code more than you would expect, usually as a parameter or a property key someone chose without thinking about it.
JSON.parse got strict
Malformed JSON that 2.0 would parse anyway now throws. This one is dangerous specifically because it is usually not your JSON. It is a partner’s payload, or a response from an external endpoint, or a field somebody pasted into a custom record five years ago with a trailing comma in it. Your code did not change and your data did not change, but the parser did.
If you are parsing anything that came from outside NetSuite, wrap it before you flip the version:
const safeParse = (raw) => {
try {
return JSON.parse(raw);
} catch (e) {
log.error({ title: 'Bad JSON', details: raw });
return null;
}
};
parseInt behaves correctly now
The old engine and the new one differ on how parseInt handles certain inputs, particularly strings with leading zeros. If you are parsing document numbers, zero-padded codes, or anything from an EDI feed, check it. This is the kind of bug that does not throw, it just produces a slightly wrong number and posts it to a record.
The fix is the one you should have been using anyway: always pass the radix.
parseInt(value, 10)
for each…in is gone
If you have any of the old for each (var x in list) syntax hanging around from very old code, it does not survive. Rewrite as a normal loop or a forEach.
A handful of smaller ones
Error object properties differ between the engines, so if you are reading specific fields off a caught error and logging or branching on them, check what you actually get. Conditional catch blocks are gone. The toSource method is gone. Date-to-local-string formats differ. Decimals with trailing zeros are set differently. RESTlets have a return type difference and a string-handling difference on POST.
None of these are common, but if your migration throws something weird and it is not on the list above, it is probably on this one.
Now the part nobody sells hard enough
Everything above is downside management. Here is what you actually get, and it is the reason I push clients to do this rather than wait for a deadline to make them.
Modern JavaScript. Arrow functions, let and const that mean something, template literals, destructuring, spread, default parameters, classes. If you have looked at the 2.1 code samples across this series and wondered why they read so much more cleanly than your 2.0 scripts, that is why. It is the same platform, written in a language from this decade.
Promises and async/await in server scripts. Not just client scripts. This changes how you write anything that chains several operations together, and it is genuinely not available to you on 2.0.
Three modules that only exist on 2.1. N/llm, which is how you call a language model from inside SuiteScript. N/pgp, for encryption and signing, which matters enormously if you exchange files with trading partners. And N/crypto/random in server scripts.
That first one deserves a sentence of its own. If anybody at your company has asked about putting AI anywhere near NetSuite, the answer is that the module for it is 2.1-only. You cannot get there from 2.0. That single fact has unstuck more migration budgets than the deprecation notice ever will.
One thing you lose
The SuiteScript Debugger does not work on 2.1. You debug 2.1 scripts in the browser debugger instead, and for server scripts that means leaning harder on logging than you may be used to.
This trips people up because it is a workflow change rather than a code change, and nobody warns you about it until you are already halfway through a bug. If your team relies on the debugger, budget a little time for them to get comfortable with the alternative before the migration, not during it.
How to actually do it
The temptation is to write a script that flips every JSDoc header in the File Cabinet at once. Do not do that. You will get a wall of failures with no way to tell which script caused what.
Do it in this order instead.
Start with the scripts you can safely re-run. Map/Reduce and scheduled scripts first, because if one fails you run it again and nothing is lost. Then Suitelets, which fail visibly and only for the person who opened the page. Then RESTlets. User Events on your highest-volume transaction records go last, because a failure there blocks a save and your sales team finds out before you do.
Change the header and nothing else. Resist the urge to modernise the code in the same commit. If something breaks you want to know it was the engine, not your refactor. Rewrite in ES6 later, as a separate piece of work, once it is running clean on 2.1.
Exercise every path in Sandbox. Not just the happy one. The error handler is where the engine differences hide, because that is where the caught-error properties and the JSON parsing and the conditional catches all live, and it is the path you never test.
Deploy in small batches. Five or ten scripts, then watch the execution logs for a few days before the next batch. If something odd turns up, your suspect list is short.
Rollback is the easiest of any migration in this series: change the header back. That is genuinely all it is.
What to do this quarter
Run the same audit we covered earlier in the series, but this time filter on API version rather than script type, and count how many scripts say 2.0. In most accounts the number is large and the work per script is close to zero, which is an unusual and very favourable ratio.
Then do the batch-one scripts. Not all of them, just the safe ones. You will learn more about what your code does wrong in that first batch than in any amount of planning, and you will have a real number to put against the rest.
The 1.0 work has a deadline and you have to do it. The 2.0 work does not have a deadline yet, which is exactly why it is worth doing now, while it is a quiet afternoon rather than a project.
The NetSuite Pro runs SuiteScript version audits and handles 1.0 and 2.0 migrations as fixed-fee engagements. Get in touch.
Discover more from The NetSuite Pro
Subscribe to get the latest posts sent to your email.
Leave a Reply