Bulk-delete NetSuite records, without the one-off scripts.
A free Suitelet + Map/Reduce utility that clears sandbox and test data by subsidiary, record type, date, and External ID — with a preview before anything is removed, and a job you can walk away from.
22
record types
5,000
unit reduce budget
1
subsidiary per job
0
third-party code
Every dry run leaves something behind.
A migration sandbox fills up fast — a few thousand test invoices, a stack of Trial Balance journal entries, a customer list nobody recognizes. NetSuite gives admins no fast way to clear it at scale, so the choice is usually deleting records one at a time, or losing an afternoon to a throwaway script you'll rewrite for the next client.
| Approach | Scales to thousands? | Repeatable? | Layered criteria? |
|---|---|---|---|
| Delete one at a time in the UI | — | — | — |
| Write a one-off SuiteScript | — | only coded | |
| Mass Delete via a saved search | partial | partial | — |
| SuiteMigration Admin Toolkit |
None of the first three scale to a request like "delete every invoice created in the last 30 days for this one subsidiary, but leave the ones with a blank External ID alone." That's the kind of targeted, repeatable cleanup a migration runs into over and over.
It's free and open source. Grab it and clear your next sandbox in one job.
Four filters, combined with AND
Each condition narrows the set, so only records that meet every selected filter are ever included for deletion.
Subsidiary
Every deletion is scoped to a single, active subsidiary — so a cleanup can never reach across into the wrong entity. Always required.
Record Type
Pick one type — Customers, Invoices, Journal Entries — or a built-in group: All Entities, All Transactions, or All Records.
External ID
Target by whether records have an External ID: all, only populated, only blanks, or specifically the ones a SuiteMigration push created.
Date Filter
By creation date (any type) or transaction date (transactions), inclusive endpoints, with a format hint matching your account's date preference.
Worked example
"Delete invoices created in the last 30 days for one subsidiary, but keep the ones with a blank External ID."
Subsidiary
The one to clean up
Record Type
Invoices
External ID
Populated only
Date Filter
Created · last 30 days
22 record types, one at a time or in bulk
Delete a single type, or clear several at once with a built-in group.
All Entities
Customers, Vendors, Employees, Items (all six subtypes), and Projects.
All Transactions
17 transaction types — invoices, payments, credits, bills, checks, deposits, POs, journal entries and more.
All Records
Everything above, for a full test-data wipe of one subsidiary in a single job.
Match exactly what SuiteMigration created
Three targets aren't standard NetSuite record types at all — they're Checks or Journal Entries identified purely by a SuiteMigration-generated External ID pattern. So you can clear exactly what a push created without touching a single manually entered record in the same subsidiary.
Cash Expenses
Stored as a Check, identified by an External ID ending
__cex_chk Transfers
Stored as a Journal Entry, identified by an External ID ending
__trf_jrn Trial Balance JEs
Journal Entries whose External ID contains
sm_net · sm_rebuild · sm_manual Want the exact script IDs, deployment settings, and a troubleshooting table?
Built around NetSuite's governance limits
The ceiling that kills hand-rolled delete scripts once a sandbox has more than a few hundred records is exactly what the toolkit is engineered around.
Runs as a background Map/Reduce job
Deletion happens in the Reduce phase, where NetSuite grants a fresh 5,000-unit governance allowance to every invocation — the same model NetSuite uses for its own large-scale processing. That's what clears tens of thousands of records without timing out.
A concurrency guard
Only one deletion job runs at a time per account, so two admins can't accidentally kick off overlapping deletes in the same environment.
Live progress, per record type
Watch a progress bar instead of guessing whether a tab is still working. Group deletes run in dependency order — payments before invoices — with a deleted/failed breakdown at the end.
Handles what breaks a hand-rolled script
Two NetSuite-specific problems a quick delete script almost always gets wrong — the toolkit takes care of both.
Customer trees, deepest-first
Deleting a Customer walks its sub-customers and grandchildren and removes them deepest-first, clears the linked contact records, and drops the vendor, employee, and subsidiary relationships that would otherwise block the delete outright — so the number actually removed can exceed the top-level count.
Items in a single pass
Items are matched across all six subtypes — Inventory, Non-Inventory, Service, Assembly, Kit, and Group — in one run, instead of needing a separate pass per item type.
Safety as the default, not an afterthought
This performs permanent, irreversible deletions — so it's built to make that hard to do by accident.
Preview before you commit
Every deletion shows exactly what will be removed — subsidiary, type, date range, External ID criteria — before you can confirm.
An explicit confirmation step
You read the summary and click through a dedicated Confirm Deletion dialog. There is no single-click delete.
Locked-in selections
Once a filter value is picked, that dropdown becomes read-only, so a stray keystroke can't quietly widen a deletion you already scoped down.
A traceable audit trail
Every job start, summary, and individual delete failure is written to NetSuite's own script execution log — so you can always see exactly what happened.
None of that changes the fundamental fact: once records are deleted, they're gone. Test in a Sandbox account before you point this anywhere near Production — it's the one thing that actually matters.
Not sure where to start? Leave your details and we'll help you deploy it.
Where it comes in handy
The migration workflow is what drove us to build it, but it covers a wider range than that.
In a migration project
- Clear a sandbox after a dry run, before the next push
- Remove only the records a specific push created, by External ID
- Clean up Trial Balance push JEs without touching manual ones
- Recover from a partial import by deleting one subsidiary/date slice
General admin work
- Reset a sandbox before handing it back to a client or team
- Bulk-remove test data from any integration or import project
- Clear a training or demo environment after a session
- Wipe a subsidiary's test data in one job via All Records
Precision & scale
- Restrict a cleanup to one subsidiary in a multi-subsidiary account
- Separate integration-created records from manual ones, clear one side
- Preview a filter combination to count matches before deleting
- Delete thousands of records in one background job
For consultants: the license covers use on behalf of your clients, so you can bring the same repeatable cleanup to every engagement instead of rewriting a delete script each time. It's free for your own org and your clients' — it just can't be resold, re-hosted, or rebranded as your own product.
Manual by design, in about 15 minutes
There's no code to write, but it does assume you're comfortable deploying SuiteScript. The deployment guide has the exact IDs, settings, screenshots, and a troubleshooting table.
Upload two files
Add the Suitelet and Map/Reduce scripts to the same NetSuite File Cabinet folder.
Create the script records
Create the Map/Reduce script with the required ID and its seven Free-Form Text parameters, then the Suitelet.
Deploy and open
Deploy both, open the Suitelet URL, and you're ready to scope your first cleanup.
Free, open source, yours today
Grab it on GitHub — no sign-up, no wall. Prefer a hand deploying it, or a heads-up when we add new tools to the Toolkit? Leave your details and we'll help you get set up. Either way, it's free.