# SuiteScript 1.0 to 2.1 API Mapping: nlapi Functions to 2.x Modules

> Source: https://netray.co/tools/netsuite-suitescript-1-0-to-2-1-api-mapping-reference
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Look up the SuiteScript 2.x module and method that replaces each common nlapi or nlobj call, with governance and behaviour differences to watch during migration.

## Category

developer

## Erp

NetSuite

## Audience

- SuiteScript developer
- NetSuite technical consultant
- NetSuite administrator

## Tool

**Kind:** worksheet

**Mode:** reference

**Columns:**

#### SuiteScript 1.0

**Key:** suitescript_1_0

**Type:** text

#### SuiteScript 2.x

**Key:** suitescript_2_x

**Type:** text

#### Module

**Key:** module

**Type:** text

#### Governance (2.x units)

**Key:** governance_note

**Type:** text

#### Gotcha

**Key:** gotcha

**Type:** text

**Rows:**

**Suitescript 1 0:** nlapiLoadRecord

**Suitescript 2 x:** record.load({type, id, isDynamic})

**Module:** N/record

**Governance note:** 10 transaction, 2 custom record, 5 other

**Gotcha:** Defaults to standard mode. Pass isDynamic: true if the 1.0 code relied on sourcing as fields were set.

**Suitescript 1 0:** nlapiCreateRecord

**Suitescript 2 x:** record.create({type, isDynamic, defaultValues})

**Module:** N/record

**Governance note:** 10 transaction, 2 custom record, 5 other

**Gotcha:** Initialize values go in defaultValues.

**Suitescript 1 0:** nlapiSubmitRecord

**Suitescript 2 x:** Record.save({enableSourcing, ignoreMandatoryFields})

**Module:** N/record

**Governance note:** 20 transaction, 4 custom record, 10 other

**Gotcha:** Options object replaces positional booleans. Returns the internal ID.

**Suitescript 1 0:** nlapiDeleteRecord

**Suitescript 2 x:** record.delete({type, id})

**Module:** N/record

**Governance note:** 20 transaction, 4 custom record, 10 other

**Gotcha:** Same unit cost as save.

**Suitescript 1 0:** nlapiTransformRecord

**Suitescript 2 x:** record.transform({fromType, fromId, toType, isDynamic})

**Module:** N/record

**Governance note:** 10 transaction, 2 custom record, 5 other

**Gotcha:** Save the returned record to commit it.

**Suitescript 1 0:** nlapiCopyRecord

**Suitescript 2 x:** record.copy({type, id, isDynamic})

**Module:** N/record

**Governance note:** 10 transaction, 2 custom record, 5 other

**Gotcha:** Returns an unsaved record.

**Suitescript 1 0:** nlapiSubmitField

**Suitescript 2 x:** record.submitFields({type, id, values, options})

**Module:** N/record

**Governance note:** 10 transaction, 2 custom record, 5 other

**Gotcha:** Values is an object. Only works on inline-editable body fields; others trigger a full load and save.

**Suitescript 1 0:** nlapiLookupField

**Suitescript 2 x:** search.lookupFields({type, id, columns})

**Module:** N/search

**Governance note:** 1

**Gotcha:** Select fields return an array of {value, text}, not a string.

**Suitescript 1 0:** nlapiAttachRecord

**Suitescript 2 x:** record.attach({record, to, attributes})

**Module:** N/record

**Governance note:** 10

**Gotcha:** record and to are {type, id} objects.

**Suitescript 1 0:** nlapiDetachRecord

**Suitescript 2 x:** record.detach({record, from, attributes})

**Module:** N/record

**Governance note:** 10

**Gotcha:** Mirror of attach.

**Suitescript 1 0:** nlapiVoidTransaction

**Suitescript 2 x:** transaction.void({type, id})

**Module:** N/transaction

**Governance note:** 10

**Gotcha:** Behaviour depends on the Void Transactions Using Reversing Journals preference.

**Suitescript 1 0:** nlapiSearchRecord

**Suitescript 2 x:** search.create({type, filters, columns}).run().getRange({start, end})

**Module:** N/search

**Governance note:** getRange 10 per call; create 0

**Gotcha:** 1.0 returned up to 1000 rows directly. In 2.x use runPaged or getRange in 1000-row pages.

**Suitescript 1 0:** nlapiCreateSearch

**Suitescript 2 x:** search.create

**Module:** N/search

**Governance note:** 0

**Gotcha:** Filters can be filter objects or a filter expression array.

**Suitescript 1 0:** nlapiLoadSearch

**Suitescript 2 x:** search.load({id})

**Module:** N/search

**Governance note:** 5

**Gotcha:** id accepts the customsearch script ID or internal ID.

**Suitescript 1 0:** nlobjSearchFilter

**Suitescript 2 x:** search.createFilter({name, join, operator, values})

**Module:** N/search

**Governance note:** 0

**Gotcha:** Use search.Operator enums, for example search.Operator.ANYOF.

**Suitescript 1 0:** nlobjSearchColumn

**Suitescript 2 x:** search.createColumn({name, join, summary, sort})

**Module:** N/search

**Governance note:** 0

**Gotcha:** Read results with result.getValue(column) or getValue({name, join}).

**Suitescript 1 0:** nlobjSearchResultSet.forEachResult

**Suitescript 2 x:** ResultSet.each(callback)

**Module:** N/search

**Governance note:** 10

**Gotcha:** Return true to continue; stops at 4000 results.

**Suitescript 1 0:** nlapiGetContext

**Suitescript 2 x:** runtime.getCurrentScript(), runtime.getCurrentUser(), runtime.getCurrentSession()

**Module:** N/runtime

**Governance note:** 0

**Gotcha:** Script parameters: runtime.getCurrentScript().getParameter({name}).

**Suitescript 1 0:** nlobjContext.getRemainingUsage

**Suitescript 2 x:** runtime.getCurrentScript().getRemainingUsage()

**Module:** N/runtime

**Governance note:** 0

**Gotcha:** Same idea, different object.

**Suitescript 1 0:** nlapiGetUser

**Suitescript 2 x:** runtime.getCurrentUser().id

**Module:** N/runtime

**Governance note:** 0

**Gotcha:** Property, not a method.

**Suitescript 1 0:** nlapiGetRole

**Suitescript 2 x:** runtime.getCurrentUser().role

**Module:** N/runtime

**Governance note:** 0

**Gotcha:** Returns the internal ID; roleId gives the script ID.

**Suitescript 1 0:** nlapiGetSubsidiary

**Suitescript 2 x:** runtime.getCurrentUser().subsidiary

**Module:** N/runtime

**Governance note:** 0

**Gotcha:** Department and location follow the same pattern.

**Suitescript 1 0:** nlapiScheduleScript

**Suitescript 2 x:** task.create({taskType: task.TaskType.SCHEDULED_SCRIPT, scriptId, deploymentId, params}).submit()

**Module:** N/task

**Governance note:** 20 for submit

**Gotcha:** Map/Reduce uses task.TaskType.MAP_REDUCE.

**Suitescript 1 0:** nlapiYieldScript, nlapiSetRecoveryPoint

**Suitescript 2 x:** No equivalent

**Module:** N/A

**Governance note:** N/A

**Gotcha:** Redesign long scheduled jobs as Map/Reduce, which yields and resumes automatically.

**Suitescript 1 0:** nlapiSendEmail

**Suitescript 2 x:** email.send({author, recipients, subject, body, attachments, relatedRecords})

**Module:** N/email

**Governance note:** 20

**Gotcha:** relatedRecords replaces the records parameter.

**Suitescript 1 0:** nlapiRequestURL

**Suitescript 2 x:** https.request / https.get / https.post (or http.*)

**Module:** N/https

**Governance note:** 10

**Gotcha:** Response body is response.body, status is response.code.

**Suitescript 1 0:** nlapiResolveURL

**Suitescript 2 x:** url.resolveRecord, url.resolveScript, url.resolveTaskLink, url.resolveDomain

**Module:** N/url

**Governance note:** 0

**Gotcha:** Split by URL type instead of one function with a type string.

**Suitescript 1 0:** nlapiSetRedirectURL

**Suitescript 2 x:** redirect.toRecord, redirect.toSuitelet, redirect.toTaskLink, redirect.redirect

**Module:** N/redirect

**Governance note:** 0

**Gotcha:** Suitelet response redirects can also use response.sendRedirect.

**Suitescript 1 0:** nlapiLogExecution

**Suitescript 2 x:** log.debug, log.audit, log.error, log.emergency

**Module:** N/log

**Governance note:** 0

**Gotcha:** Global log object; the deployment Log Level filters what is stored.

**Suitescript 1 0:** nlapiCreateError

**Suitescript 2 x:** error.create({name, message, notifyOff})

**Module:** N/error

**Governance note:** 0

**Gotcha:** Throw the returned object.

**Suitescript 1 0:** nlapiLoadFile

**Suitescript 2 x:** file.load({id})

**Module:** N/file

**Governance note:** 10

**Gotcha:** id accepts internal ID or File Cabinet path.

**Suitescript 1 0:** nlapiCreateFile

**Suitescript 2 x:** file.create({name, fileType, contents, folder})

**Module:** N/file

**Governance note:** 0

**Gotcha:** Set folder before File.save().

**Suitescript 1 0:** nlapiSubmitFile

**Suitescript 2 x:** File.save()

**Module:** N/file

**Governance note:** 20

**Gotcha:** Returns the file internal ID.

**Suitescript 1 0:** nlapiCreateForm

**Suitescript 2 x:** serverWidget.createForm({title, hideNavBar})

**Module:** N/ui/serverWidget

**Governance note:** 0

**Gotcha:** Added field IDs must start with custpage.

**Suitescript 1 0:** nlapiCreateList

**Suitescript 2 x:** serverWidget.createList({title})

**Module:** N/ui/serverWidget

**Governance note:** 0

**Gotcha:** Suitelet only.

**Suitescript 1 0:** nlapiCreateAssistant

**Suitescript 2 x:** serverWidget.createAssistant({title})

**Module:** N/ui/serverWidget

**Governance note:** 0

**Gotcha:** Suitelet only.

**Suitescript 1 0:** nlapiDateToString, nlapiFormatCurrency

**Suitescript 2 x:** format.format({value, type: format.Type.DATE | CURRENCY})

**Module:** N/format

**Governance note:** 0

**Gotcha:** Uses the user's date and number preferences.

**Suitescript 1 0:** nlapiStringToDate

**Suitescript 2 x:** format.parse({value, type: format.Type.DATE})

**Module:** N/format

**Governance note:** 0

**Gotcha:** Returns a Date object. setValue on date fields expects Date, not a string.

**Suitescript 1 0:** nlapiXMLToPDF

**Suitescript 2 x:** render.xmlToPdf({xmlString})

**Module:** N/render

**Governance note:** 10

**Gotcha:** Returns a file.File object.

**Suitescript 1 0:** nlapiCreateTemplateRenderer

**Suitescript 2 x:** render.create()

**Module:** N/render

**Governance note:** 0

**Gotcha:** Then setTemplateById or templateContent, addRecord, renderAsPdf.

**Suitescript 1 0:** nlapiGetFieldValue / nlapiSetFieldValue

**Suitescript 2 x:** Record.getValue({fieldId}) / Record.setValue({fieldId, value})

**Module:** N/record, N/currentRecord

**Governance note:** 0

**Gotcha:** Values are typed: checkboxes are booleans, dates are Date objects.

**Suitescript 1 0:** nlapiGetFieldText / nlapiSetFieldText

**Suitescript 2 x:** Record.getText / Record.setText

**Module:** N/record

**Governance note:** 0

**Gotcha:** getText on a standard mode record works only after setText or load.

**Suitescript 1 0:** nlapiGetLineItemValue / nlapiSetLineItemValue

**Suitescript 2 x:** Record.getSublistValue / setSublistValue({sublistId, fieldId, line, value})

**Module:** N/record

**Governance note:** 0

**Gotcha:** Lines are 0-based in 2.x, 1-based in 1.0. Sublist IDs are lower case (item, not Item).

**Suitescript 1 0:** nlapiGetLineItemCount

**Suitescript 2 x:** Record.getLineCount({sublistId})

**Module:** N/record

**Governance note:** 0

**Gotcha:** Use it as the loop bound: lines run from 0 to count - 1.

**Suitescript 1 0:** nlapiSelectNewLineItem / nlapiCommitLineItem

**Suitescript 2 x:** Record.selectNewLine / Record.commitLine({sublistId})

**Module:** N/record (dynamic), N/currentRecord

**Governance note:** 0

**Gotcha:** Dynamic mode only; use setCurrentSublistValue between select and commit.

**Suitescript 1 0:** nlapiFindLineItemValue

**Suitescript 2 x:** Record.findSublistLineWithValue({sublistId, fieldId, value})

**Module:** N/record

**Governance note:** 0

**Gotcha:** Returns a 0-based index or -1.

**Suitescript 1 0:** nlapiGetNewRecord / nlapiGetOldRecord

**Suitescript 2 x:** context.newRecord / context.oldRecord

**Module:** Entry point context

**Governance note:** 0

**Gotcha:** Read-only in afterSubmit; reload to change and save.

**Suitescript 1 0:** nlapiInitiateWorkflow / nlapiTriggerWorkflow

**Suitescript 2 x:** workflow.initiate / workflow.trigger

**Module:** N/workflow

**Governance note:** 20

**Gotcha:** Workflow ID accepts the customworkflow script ID.

**Suitescript 1 0:** nlapiExchangeRate

**Suitescript 2 x:** currency.exchangeRate({source, target, date})

**Module:** N/currency

**Governance note:** 10

**Gotcha:** Source and target accept ISO code or internal ID.

**Notes:** Mappings follow the SuiteScript 1.0 to SuiteScript 2.x API Map in NetSuite help. Governance values are the SuiteScript 2.x unit costs; recheck them in help for your release. 2.1 scripts declare @NApiVersion 2.1 in the JSDoc header.

## Content

**Intro:** This table maps the nlapi functions and nlobj objects you find in legacy SuiteScript 1.0 code to the SuiteScript 2.x module and method that replaces them. Use it while rewriting a 1.0 script as 2.1, or while reading old code to understand what it does.

**Sections:**

#### How to use it

**Body:** Search for the 1.0 function name you are replacing, for example nlapiSubmitField. The 2.x column gives the call and its options object, Module tells you which define dependency to add, and the governance column shows the 2.x unit cost so you can recheck the script's budget. The Gotcha column is where most migration bugs hide: typed values, 0-based line indexes and different return shapes. Work through a script top to bottom, list every distinct nlapi call, and look each one up before you touch the logic. Rows marked No equivalent mean a redesign, not a rename.

#### SuiteScript 2.1 basics you need for the rewrite

**Body:** A 2.1 script starts with a JSDoc block containing @NApiVersion 2.1 and @NScriptType (for example UserEventScript or MapReduceScript), then a define call that loads modules such as N/record and N/search and returns the entry points. 2.1 runs on a newer JavaScript engine and accepts ES2019-era syntax such as let, const, arrow functions, destructuring and spread. 1.0 and 2.x APIs cannot be mixed in one file. A 1.0 script record cannot simply point to a 2.1 file; create a new script record, deploy it, test, then set the old deployment to not deployed. Recreate the script parameters on the new script record and value them on the new deployment.

#### Worked example

**Body:** A 1.0 user event calls nlapiLookupField('customer', custId, 'creditlimit'), then nlapiSubmitField('salesorder', soId, 'custbody_hold', 'T'). In 2.1 this becomes search.lookupFields({type: search.Type.CUSTOMER, id: custId, columns: ['creditlimit']}).creditlimit, then record.submitFields({type: record.Type.SALES_ORDER, id: soId, values: {custbody_hold: true}}). Note the checkbox is now a boolean true instead of 'T'. If the lookup were a select field, the result would be an array of objects with value and text, so code that compared a string would silently fail. Governance stays the same in this example: 1 unit for the lookup and 10 for submitFields on a transaction.

#### Common mistakes

**Body:** The three bugs that show up in almost every migration are 1-based line loops copied into 2.x, so the last line is skipped or line 0 is missed; string dates passed to setValue on a date field, which throws INVALID_FLD_VALUE; and searches that returned 1000 rows in 1.0 now returning nothing because run() was called but getRange or each was not. Also watch nlapiYieldScript loops: there is no yield in 2.x scheduled scripts, so long jobs belong in Map/Reduce. Finally, 2.x context objects differ per entry point, so check context.type against context.UserEventType enums instead of the string 'create'.

**Bullets:**

- Loop lines from 0 to getLineCount() - 1
- Pass Date objects to date fields, booleans to checkboxes
- Use runPaged for result sets over a few thousand rows

**Cta:** If you want a private AI assistant that reads your legacy SuiteScript and drafts the 2.1 version for your developers to review, running on your own servers, we can set that up.

**Faq:**

#### Should I migrate SuiteScript 1.0 to 2.0 or 2.1?

**Answer:** Target 2.1 for new work. It uses the same modules as 2.0 but supports modern JavaScript syntax, and Oracle documents new capabilities against 2.x. 1.0 still runs, but Oracle no longer adds new features to it and new APIs are not exposed to it. Migrate the scripts you change most often first.

#### What replaces nlapiSearchRecord in SuiteScript 2.1?

**Answer:** search.create with type, filters and columns, then run() and either getRange({start: 0, end: 1000}) or each(callback). For more than a few thousand rows use search.runPaged and fetch each page. You can also query with N/query or query.runSuiteQL if SuiteQL is a better fit for the joins you need.

#### Is there a SuiteScript 2.x equivalent of nlapiYieldScript?

**Answer:** No. Scheduled scripts in 2.x cannot yield and resume. Long-running work should be rewritten as a Map/Reduce script, which splits input into map and reduce stages, manages governance per stage and yields automatically based on the deployment's yield settings.

#### Can I call SuiteScript 1.0 functions from a 2.1 script?

**Answer:** No. A script file is either 1.0 or 2.x. The nlapi functions are not available in 2.x scripts and 2.x modules are not available in 1.0. During migration you can run both versions side by side as separate script records and deployments, then turn off the old one.

## Search terms

netsuite suitescript 1.0, netsuite transitioning to suitescript 2.1, netsuite suitescript api documentation, netsuite suitescript, suitescript 1.0 to 2.0 mapping, nlapiLoadRecord 2.0 equivalent, nlapiSearchRecord suitescript 2.1, suitescript 2.1 migration

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
