Your NetSuite Account Has 150 Scripts. Zero Are in Git.
I’ve audited a lot of NetSuite accounts. The pattern is almost always the same.
You open the SuiteScript folder in the File Cabinet. There’s fulfillment_script.js. And fulfillment_script_v2.js. And fulfillment_script_v2_FINAL.js. And fulfillment_script_v2_FINAL_fixed.js.
Nobody knows which one is actually deployed. The developer who wrote it left two years ago. There’s no Git history, no commit messages, no way to see what changed between versions - or why.
This is where most NetSuite accounts end up. But it doesn’t have to stay that way.
Why this keeps happening
NetSuite makes version control unintuitive. The whole development model works against it.
In normal software development, every developer has their own machine, their own local copy of the code, and Git handles the rest. In NetSuite, everyone shares the same sandbox. You upload a script, I upload a script, and whoever went last wins. There’s no merge conflict warning. No diff. No history. Just overwritten work and a lot of Slack messages that start with “did you change something?”
The File Cabinet is not version control. Saved copies are not version control. A naming convention with _v3_FINAL is definitely not version control.
SDF gives you a way out
SuiteCloud Development Framework gives you something the File Cabinet never could - a local, file-based representation of your NetSuite customizations that you can actually put in Git.
Here’s what setting up a new SDF project looks like:
$ suitecloud project:create -i
? Choose the project type: Account Customization Project
? Enter the project name: my-netsuite-project
? Enter the publisher ID: com.suitedynamix
Project "my-netsuite-project" created successfully.
That gives you a real project structure on your filesystem:
$ tree my-netsuite-project/
my-netsuite-project/
├── src/
│ ├── FileCabinet/
│ │ └── SuiteScripts/
│ ├── Objects/
│ └── AccountConfiguration/
├── manifest.xml
└── project.json
Now your scripts live on your machine. In files. That you can commit.
Git from day one
Once you have an SDF project, Git is straightforward:
$ cd my-netsuite-project
$ git init
Initialized empty Git repository in /projects/my-netsuite-project/.git/
$ git add .
$ git commit -m "initial SDF project setup"
[main (root-commit) 3a7f1c2] initial SDF project setup
4 files changed, 87 insertions(+)
Now every change has a history. Every deployment has a paper trail. When something breaks in production three weeks from now, you can do this:
$ git log --oneline
e4b21a9 fix: handle null line values in fulfillment UE
8c0f3d1 feat: add inventory adjustment validation
3a7f1c2 initial SDF project setup
And then:
$ git diff 8c0f3d1..e4b21a9 -- src/FileCabinet/SuiteScripts/fulfillment_ue.js
You can see exactly what changed, when, and in the commit message - why.
Branching
I’ve seen teams try to implement full GitFlow with NetSuite and it falls apart within a week. Too many branches, too much ceremony.
What I use is simpler:
# main branch = what's in production
# develop branch = what's in sandbox
# feature branches = what you're working on right now
$ git checkout -b feature/inventory-validation
Switched to a new branch 'feature/inventory-validation'
# ... write your script, test in sandbox ...
$ git add src/FileCabinet/SuiteScripts/inventory_validation_ue.js
$ git commit -m "feat: validate negative quantities on inventory adjustments"
$ git checkout develop
$ git merge feature/inventory-validation
For most NetSuite instances, three branches is all you need. main mirrors production. develop mirrors sandbox. Feature branches for anything in progress. Larger teams or multi-subsidiary environments might need more structure, but this covers the majority of accounts I’ve worked with.
How the code gets deployed from those branches is where CI/CD comes in.
Importing an existing account
Setting up Git on a new project is easy. The harder part is taking an existing account with 150 scripts already living in the File Cabinet and pulling them into SDF.
$ suitecloud project:import --paths /SuiteScripts
This pulls your existing scripts down into the local SDF project. From there, you commit them as your baseline:
$ git add .
$ git commit -m "import existing scripts from file cabinet"
[main 7f2c4b8] import existing scripts from file cabinet
153 files changed, 24891 insertions(+)
153 files. 24,891 lines. All of it now tracked. All of it now diffable. That’s your starting point.
What this prevents
I worked with a team where two developers were building scripts that touched the same record type. Developer A deployed on Monday. Developer B deployed on Wednesday - and unknowingly overwrote A’s changes. They didn’t realize it until a week later when a workflow started failing in production.
With Git, that scenario plays out differently:
$ git merge feature/developer-b-changes
Auto-merging src/FileCabinet/SuiteScripts/sales_order_ue.js
CONFLICT (content): Merge conflict in sales_order_ue.js
Automatic merge failed; fix conflicts and then commit the result.
The conflict gets caught before deployment. Not a week later in production.
Automating deploys with CI/CD
Once Git and SDF are in place, there’s no reason anyone should still be deploying manually. Most software teams automated this years ago - merge a pull request and the pipeline handles the rest. NetSuite should be no different.
Here’s what that looks like:
- You write code on a feature branch. Test it locally with
suitecloud project:validate. Push it to your remote repo. - You open a pull request. Your team reviews the diff - actual code changes, not a Slack message saying “I uploaded something.”
- You merge to
develop. A CI/CD pipeline picks up the merge, authenticates against your sandbox account, and deploys. No one had to open a terminal or remember which flags to pass. - QA signs off. You open a PR from
developtomain. - You merge to
main. The production pipeline runs - but only after someone on the team approves it. No accidental production pushes. No “I thought we were deploying to sandbox.”
Every step has a record. Every change has a review. Every deploy has an audit trail.
Whatever CI/CD platform your team already uses works fine. The SuiteCloud CLI runs in any of them. The pipeline installs it, authenticates with a token, validates the project, and deploys.
You can layer on more over time - linting, unit tests, Slack notifications when a deploy succeeds or fails. But even the bare-bones version where a merge triggers a deploy is a massive improvement. The deployment process goes from “that thing only one person knows how to do” to a button in a pull request.
And once deploys are automated and auditable, people stop being afraid to ship. When every change goes through a PR, code quality goes up without anyone having to police it. The pipeline enforces the process so the team doesn’t have to think about it.
The real issue
Most NetSuite developers already know what they should be doing. The problem is that the NetSuite development environment makes it so easy to be lazy and take shortcuts. Upload directly to the File Cabinet? Works. Skip the commit? Nobody’s checking. Deploy from your laptop without telling anyone? Done before lunch.
The platform doesn’t punish bad habits until it’s too late. That’s why the setup matters - not because developers don’t know better, but because the tooling should make the right way the easy way.