A language for NetSuite
Mynt
What SuiteScript could look like, if it were designed today.
A small language that compiles to plain SuiteScript 2.1 – written by a NetSuite developer who spent four years writing the same ceremony around every idea, and finally asked whether it had to be there.
scheduled { let orders = query SalesOrder for row in orders { let order = load SalesOrder(row.id) for line in order.item { if line.quantity < 1 { line.quantity = 1 } } save order } }
v0.1.0 · MIT licensed · Compiles to SuiteScript 2.1
Origin
It started as a list of detours
Since 2022 most of my working days have been spent inside NetSuite: user events and scheduled scripts for four companies, integrations that move orders and customers between systems, and a growing pile of tooling to make SuiteScript development less repetitive. It is good work. Real businesses run on it, and the problems are concrete – an invoice that should not exist, a field nobody set, a sync that has to survive the other system being down.
But the same detours kept turning up around the work. A field is a
string you hope is spelled right, and you find out it is not when the script fails in
production. Every file opens with a list of modules written out by hand. Setting one value
takes an object, a key called fieldId and a key called value.
And a change written to a record in the wrong entry point does not fail at all – it is
quietly thrown away.
So I built tools. TypeScript for the types, a CLI for the project layout, an integration platform so the next integration would not need a developer. Each one sanded off an edge. None of them changed the shape underneath.
The question
Fundamental, or inherited?
After enough of them, I started sorting the problems into two piles. Some of the difficulty in a NetSuite script is the business: what should happen to an order, and when. That part does not go away, and should not. But much of the rest was something else – the shape of an API designed a decade ago, a module system chosen for the browsers of its day, conventions that exist because they always have.
Fred Brooks called the second pile accidental complexity. My question was narrower, and more practical than academic.
If you started from what a NetSuite developer actually does all day, what would the language look like?
beforeSubmit create | edit (customer: Customer) { customer.comments = 'Managed by Mynt' }
/** * @NApiVersion 2.1 * @NScriptType UserEventScript * @NModuleScope SameAccount * Generated by Mynt from examples/customer.mn. Target record: customer. */ define([], () => { function beforeSubmit(context) { if ( context.type !== context.UserEventType.CREATE && context.type !== context.UserEventType.EDIT ) { return; } const customer = context.newRecord; customer.setValue({ fieldId: "comments", value: "Managed by Mynt" }); } return { beforeSubmit }; });
Point at a line of Mynt to see what it becomesTap a line of Mynt to see what it becomes
Both of these are the same script. The one on the right is what Mynt writes for you – ordinary SuiteScript, deployed like any other file. Nothing in it was written by hand, and nothing in it is wrong. It is just a lot of words for one idea.
Principles
A few rules, held firmly
Mynt is small on purpose. Every rule in it answers something I have watched go wrong in a real account, and the compiler enforces all of them.
-
The platform is the type system
CustomerandSalesOrderare types, with fields pulled from your own account. A misspelled field is an error on your machine, not in an execution log. -
Operations are verbs, platform objects are types
load,create,copy,transform,save. One verb, and the type after it decides what happens. You never name a module to do it. -
Nothing to wire
One file is one script. The entry point decides the script type, and the modules come from what you actually used.
-
Persistence is not a guess
Records you load are yours to save; records NetSuite hands you are not. The compiler follows every path through a script and says where a change can be lost.
-
The output belongs to you
Plain, readable SuiteScript 2.1, with no runtime. Stop using Mynt tomorrow and what you have is ordinary code.
-
Fewer rules, no exceptions
Statements end at newlines. Conditions are booleans or they are errors. There is very little to learn, and nothing to remember the compiler will not.
The rule I wanted first is the quietest failure in SuiteScript: changing a record after NetSuite has already saved it. The platform accepts it and discards it. Mynt will not build it.
mynt check late.mn error MYNT1007: Cannot assign Customer.comments in afterSubmit: the Customer is already saved and the change would be silently discarded. Use beforeSubmit instead. late.mn:2:5 2 | customer.comments = 'Too late' | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Why me
Built from inside an ERP
There are a great many experimental programming languages, and most of them come from people who study languages. That is where the good ideas usually come from, and Mynt borrows several: newlines that end statements the way Go's do, operations that take their meaning from a type, a compiler that reasons about every path through a program.
What it has that they do not is the account. I am not a language researcher; I am a NetSuite developer, and the rules come from the job – from reviewing scripts, from chasing a change that never landed through an execution log, from explaining to someone new why a field is a string. That is both the limitation and the point. Mynt is narrow because the problems it answers are specific, and it is specific because I have had them.
Status
Early, and published early
Mynt is at 0.1.0, and it is honest about being a first version. It
writes user event and scheduled scripts today, with records and fields, sublists,
queries and searches, functions, and the rules about when a record is saved.
mynt schema pull copies your account's records and fields into the
repository, so the compiler checks against what is really there and never touches the
network. A language server gives an editor hover, completion and rename.
- Version
- 0.1.0, on npm since October 2026.
- Compiles to
- SuiteScript 2.1, deployed as-is.
- Writes
- User event and scheduled scripts.
- Licence
- MIT, and open to proposals.
Where it goes
Scripts that read like the business
The near goal is coverage. The roadmap lists every method in SuiteScript 2.1, shows which ones Mynt already compiles – with real compiler output beside each – and the syntax proposed for the rest. Client scripts, Map/Reduce, RESTlets and Suitelets are the obvious next ground.
The longer goal is harder to put on a roadmap. I would like a NetSuite script to read like a description of what the business wants – these orders, these lines, save them – with the platform's rules kept by the compiler rather than remembered by the developer. If someone new to NetSuite can spend their first week learning the business instead of the ceremony around it, Mynt will have done its job.
It is not mine alone to decide, either. Syntax for each new API is proposed in the open, in GitHub Discussions, by anyone who writes SuiteScript and has an opinion about it.
Try it on one script
npm install -g @felixdivall/mynt