SuiteScript 1.0 uses global functions prefixed with nlapi and objects prefixed with nlobj. SuiteScript 2.x, and therefore SuiteScript 2.1, replaces this pattern with modules such as N/record, N/search, N/runtime, and N/ui/serverWidget, along with methods and properties that depend on the object being used. SuiteScript 2.0 introduced this module-based API, and SuiteScript 2.1 keeps it while running scripts on a newer JavaScript runtime.
For example, nlapiLoadRecord() maps to record.load() in N/record, while nlapiSearchRecord() maps to search methods in N/search. Some legacy APIs map to multiple methods, some map to properties instead of methods, and others have no direct equivalent.
Oracle’s official SuiteScript 1.0 to 2.1 API map is the reference of record, but it is organized alphabetically, and many entries list the replacement without explaining what changes in the code. This guide is designed to sit alongside it. It groups commonly used nlapi functions and nlobj objects by task, identifies their SuiteScript 2.1 equivalents, and highlights the differences that require code changes rather than a simple name replacement. In short, Oracle’s map shows what maps; this guide flags what breaks.
Because SuiteScript 2.0 and 2.x are also being phased out, SuiteScript 1.0 scripts should be converted directly to 2.1 rather than to 2.0 or 2.x.
SuiteScript 1.0 vs. SuiteScript 2.1 API Mapping (Top 10 at a glance)
The main difference is how scripts access NetSuite functionality. SuiteScript 1.0 exposes many operations through global functions, whereas SuiteScript 2.1 organizes functionality into modules with explicit dependencies.
| SuiteScript 1.0 pattern | SuiteScript 2.1 equivalent | Module |
|---|---|---|
nlapiLoadRecord() | record.load() | N/record |
nlapiCreateRecord() | record.create() | N/record |
nlapiDeleteRecord() | record.delete() | N/record |
nlapiSearchRecord() | search.create() or search.load(), depending on the original search | N/search |
nlapiLookupField() | search.lookupFields() | N/search |
nlapiGetContext() | Relevant methods such as runtime.getCurrentScript() and runtime.getCurrentUser() | N/runtime |
nlapiCreateForm() | serverWidget.createForm() | N/ui/serverWidget |
nlapiCreateFile() | file.create() | N/file |
nlapiRequestURL() | The appropriate HTTP method, such as http.get() or http.post() | N/http |
nlapiLogExecution() | log.debug(), log.audit(), log.error(), or log.emergency() | N/log |
These mappings identify the likely replacement, not necessarily the complete conversion. For example, nlapiSearchRecord() may require search.create() or search.load(), followed by the appropriate execution and result-handling logic.
The official references for SuiteScript 1.0 functions (nlapi) and SuiteScript 1.0 objects (nlobj) provide the detailed method-level mappings.
SuiteScript 1.0 nlapi to SuiteScript 2.1 API Map
This guide covers commonly used SuiteScript 1.0 APIs and their SuiteScript 2.1 equivalents, with conversion notes for cases where the replacement requires additional changes. For the complete API mapping, refer to Oracle’s official SuiteScript 1.0 to 2.1 API map.
Record operations
The N/record module handles record creation, loading, copying, saving, deletion, and other record operations. The exact replacement depends on whether the original script works with a saved record, a current UI record, or a record supplied through a script entry point.
| SuiteScript 1.0 function | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlapiCreateRecord(type) | record.create(options) | N/record | Supply the record type and any required options. |
nlapiLoadRecord(type, id) | record.load(options) | N/record | Supply the record type and internal ID. |
nlapiCopyRecord(type, id) | record.copy(options) | N/record | Review default values and the copied record’s behavior. |
nlapiSubmitRecord(record) | Record.save() | N/record | Save the converted record object after applying the required changes. |
nlapiDeleteRecord(type, id) | record.delete(options) | N/record | Confirm that the record type and ID are correct. |
nlapiAttachRecord(...) | record.attach(options) | N/record | Specify the source record and the record to which it is attached. |
nlapiDetachRecord(...) | record.detach(options) | N/record | Specify the relevant record references. |
nlapiLookupField(type, id, fields) | search.lookupFields(options) | N/search | Review the returned value structure, particularly for select and multiselect fields. |
The nlapiSubmitRecord() mapping is commonly relevant when a legacy script loads or creates a record, changes its fields, and saves it. In SuiteScript 2.1, the save operation belongs to the record object returned by record.load() or record.create().
Field and sublist operations
Field access changes from legacy getter and setter functions to methods on record objects. SuiteScript 2.1 also distinguishes between standard-mode record operations, dynamic-mode operations, and current-record interactions in the user interface.
| SuiteScript 1.0 function | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlapiGetFieldValue(fieldId) | Record.getValue(options) or CurrentRecord.getValue(options) | N/record or N/currentRecord | Use the record object appropriate to the script context. |
nlapiGetFieldText(fieldId) | Record.getText(options) or CurrentRecord.getText(options) | N/record or N/currentRecord | Use this when the display text is required instead of the stored value. |
nlapiSetFieldValue(fieldId, value) | Record.setValue(options) or CurrentRecord.setValue(options) | N/record or N/currentRecord | Confirm field type and sourcing behavior. |
nlapiGetLineItemCount(sublistId) | Record.getLineCount(options) or CurrentRecord.getLineCount(options) | N/record or N/currentRecord | Specify the sublist ID. |
nlapiGetLineItemValue(sublistId, fieldId, line) | Record.getSublistValue(options) or CurrentRecord.getSublistValue(options) | N/record or N/currentRecord | SuiteScript 2.1 uses zero-based sublist line indexes. |
nlapiGetLineItemText(sublistId, fieldId, line) | Record.getSublistText(options) or CurrentRecord.getSublistText(options) | N/record or N/currentRecord | Check whether the script needs text or the stored field value. |
nlapiSetLineItemValue(sublistId, fieldId, line, value) | Record.setSublistValue(options) or the appropriate current-record sublist method | N/record or N/currentRecord | The correct method depends on record mode and script context. |
nlapiSelectLineItem(sublistId, line) | Record.selectLine(options) or CurrentRecord.selectLine(options) | N/record or N/currentRecord | Dynamic-mode operations require the relevant line-selection sequence. |
nlapiCommitLineItem(sublistId) | Record.commitLine(options) or CurrentRecord.commitLine(options) | N/record or N/currentRecord | Relevant to dynamic-mode sublist operations. |
Important indexing difference: SuiteScript 1.0 uses one-based line numbering for sublists, while SuiteScript 2.1 uses zero-based indexing for these APIs. A legacy reference to line 1 therefore does not automatically become a reference to line 1 in the new code. Review loops, line selection, and line-level updates during conversion.
The distinction between N/record and N/currentRecord also matters. N/record is used for record operations in server-side and other supported contexts, while N/currentRecord provides access to the current record in client-side scripts.
Search operations
SuiteScript 1.0 search functions do not always map to a single SuiteScript 2.1 method. The replacement depends on whether the legacy code creates a search, loads a saved search, retrieves a field value, or processes results.
| SuiteScript 1.0 function | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlapiCreateSearch(type, filters, columns) | search.create(options) | N/search | Define the record type, filters, and columns. |
nlapiLoadSearch(type, id) | search.load(options) | N/search | Load an existing saved search by its internal ID. |
nlapiSearchRecord(type, id, filters, columns) | search.create(options) or search.load(options) | N/search | Choose the creation or loading method based on the original logic. |
nlapiLookupField(type, id, fields) | search.lookupFields(options) | N/search | Useful for retrieving selected field values without loading the full record. |
nlapiSearchGlobal(keywords) | search.global(options) | N/search | Review the search terms and expected result handling. |
nlapiSearchDuplicate(type, fields, id) | search.duplicates(options) | N/search | Confirm that the duplicate-search criteria remain equivalent. |
A search conversion is incomplete if it only replaces the search creation function. You also need to review how the search executes, how results are retrieved, and whether the original script relies on sorting, joined columns, summary results, or a particular result limit.
Runtime, logging, and error handling
Runtime and logging functions provide information about the executing script, current user, and execution results. SuiteScript 2.1 separates these responsibilities across modules and methods.
| SuiteScript 1.0 function | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlapiGetContext() | runtime.getCurrentScript(), runtime.getCurrentUser(), or runtime.getCurrentSession() | N/runtime | Select the method that provides the required context information. |
nlapiGetUser() | runtime.getCurrentUser() | N/runtime | Review the user properties required by the script. |
nlapiGetRole() | runtime.getCurrentUser().role | N/runtime | The role is accessed through the current user object. |
nlapiGetDepartment() | runtime.getCurrentUser().department | N/runtime | The department is a user property. |
nlapiGetLocation() | runtime.getCurrentUser().location | N/runtime | The location is a user property. |
nlapiCreateError(code, details, suppressNotification) | error.create(options) | N/error | Review the error name, message, and notification behavior. |
nlapiLogExecution(type, title, details) | log.debug(), log.audit(), log.error(), or log.emergency() | N/log | Select the method that matches the intended severity and logging behavior. |
For nlapiGetContext(), the correct replacement depends on what the legacy script reads from the context. A script that needs its own deployment parameters may use runtime.getCurrentScript(), while a script that needs information about the current user should use runtime.getCurrentUser().
Logging also requires more than renaming a function. SuiteScript 1.0 passes the log type as the first argument to nlapiLogExecution(), for example nlapiLogExecution('DEBUG', 'Customer Email', email). SuiteScript 2.1 replaces that argument with a separate method for each level (log.debug(), log.audit(), log.error(), and log.emergency()) and passes the title and details as an options object, for example log.debug({ title: 'Customer Email', details: email }). The deployment’s log-level setting still controls which messages appear in the execution log, just as it did in SuiteScript 1.0. One change is easy to miss: log and util are reserved words in SuiteScript 2.1, so any 1.0 script that uses either one as a variable or function name must rename it during conversion.
Files, URLs, HTTP, and rendering
These functions cover file operations, outbound requests, URL resolution, and document generation. The correct module depends on whether the script is working with files, making an HTTP request, resolving a NetSuite URL, or generating output.
| SuiteScript 1.0 function | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlapiCreateFile(name, type, contents) | file.create(options) | N/file | Review file type, contents, encoding, and folder handling. |
nlapiLoadFile(id) | file.load(options) | N/file | Supply the file’s internal ID. |
nlapiDeleteFile(id) | file.delete(options) | N/file | Confirm the file reference and required permissions. |
nlapiRequestURL(url, ...) | http.get(), http.post(), http.put(), http.delete(), or http.request() | N/http | Choose the method based on the request and its payload. |
nlapiRequestURLWithCredentials(...) | https.request(options) | N/https | Server-side use and credential handling require particular attention. |
nlapiResolveURL(...) | url.resolveRecord(), url.resolveScript(), or url.resolveTaskLink() | N/url | Select the method based on the URL being resolved. |
nlapiCreateEmailMerger(templateId) | render.mergeEmail(options) | N/render | Review template and record inputs. |
nlapiCreateTemplateRenderer() | render.create() | N/render | Configure the renderer and supply the required data. |
nlapiXMLToPDF(xmlString) | render.xmlToPdf(options) | N/render | Validate the XML input and generated PDF output. |
For HTTP requests, the replacement must preserve the original method, headers, payload, authentication requirements, and response handling. A conversion that changes the request method or omits required headers can break an integration even if the script compiles.
SuiteScript 1.0 nlobj to SuiteScript 2.1 Object Map
The nlobj prefix identifies legacy objects and their methods. SuiteScript 2.1 maps these objects to module-specific objects, such as record.Record, search.Result, serverWidget.Form, and http.ServerRequest.
Record and field objects
| SuiteScript 1.0 object or method | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlobjRecord | record.Record or currentRecord.CurrentRecord | N/record or N/currentRecord | Select the object based on the script context. |
nlobjRecord.getFieldValue() | Record.getValue() or CurrentRecord.getValue() | N/record or N/currentRecord | Uses field IDs and options appropriate to the method. |
nlobjRecord.setFieldValue() | Record.setValue() or CurrentRecord.setValue() | N/record or N/currentRecord | Review record mode and field sourcing. |
nlobjRecord.getLineItemValue() | Record.getSublistValue() or CurrentRecord.getSublistValue() | N/record or N/currentRecord | Update line indexing and sublist options. |
nlobjRecord.getRecordType() | Record.type | N/record | The record type is a property. |
nlobjRecord.getId() | Record.id | N/record | The internal ID is a property. |
nlobjField | serverWidget.Field or record.Field | N/ui/serverWidget or N/record | Use serverWidget.Field for Suitelet form fields and record.Field for record field metadata. |
nlobjError | SuiteScriptError | N/error | Properties such as name, message, and stack replace some legacy getter methods. |
Search objects
| SuiteScript 1.0 object | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlobjSearch | search.Search | N/search | Represents a search definition. |
nlobjSearchColumn | search.Column | N/search | Review column definitions and sorting. |
nlobjSearchFilter | search.Filter | N/search | Rebuild filter expressions using the supported options. |
nlobjSearchResult | search.Result | N/search | Review how field values, text values, and joined results are retrieved. |
nlobjSearchResultSet | search.ResultSet | N/search | Review result iteration and retrieval limits. |
Suitelet request, response, form, and sublist objects
| SuiteScript 1.0 object or method | SuiteScript 2.1 equivalent | Module | Conversion note |
|---|---|---|---|
nlobjRequest | http.ServerRequest | N/http or N/https | Request properties such as parameters, headers, and body are accessed through the supported request object. |
nlobjResponse | http.ServerResponse | N/http or N/https | Review response headers, content, and output methods. |
nlobjForm | serverWidget.Form | N/ui/serverWidget | Form creation and field configuration use the serverWidget module. |
nlobjSublist | serverWidget.Sublist | N/ui/serverWidget | Methods and properties differ depending on the sublist operation. |
nlobjSublist.setLineItemValue() | Sublist.setSublistValue(options) | N/ui/serverWidget | Supply the field ID, line number, and value using the new options structure. |
nlobjSublist.getLineItemCount() | Sublist.lineCount | N/ui/serverWidget | The line count is a property. |
nlobjFile | file.File | N/file | File metadata and content operations use the file object and its methods or properties. |
The official SuiteScript 1.0 to 2.1 object map includes additional nlobj objects and methods, including assistants, fields, forms, portlets, requests, responses, search results, sublists, and subrecords.
SuiteScript 1.0 APIs That Do Not Have Direct Equivalents
Some legacy APIs require a different implementation in SuiteScript 2.1. A migration plan should identify these cases before code conversion because a direct method replacement may not exist.
| SuiteScript 1.0 API | SuiteScript 2.1 approach | What changes |
|---|---|---|
nlapiAddDays(date, days) | Use standard JavaScript date operations or an appropriate date library | There is no direct SuiteScript 2.1 API equivalent. |
nlapiAddMonths(date, months) | Use standard JavaScript date operations or an appropriate date library | Calendar behavior needs careful validation, particularly around month boundaries. |
nlapiYieldScript() | Reassess the script design and use the appropriate supported script type and execution model | Scheduled-script recovery points are no longer necessary in the same way. |
nlobjSubrecord.commit() and nlobjSubrecord.cancel() | Use the SuiteScript 2.1 subrecord model | Subrecord handling differs fundamentally from SuiteScript 1.0. |
nlobjSublist.setLineItemValues() | Set individual sublist values using supported methods | There is no direct equivalent for this bulk method. |
nlapiRefreshLineItems() | Reassess the original purpose and current script behavior | There is no direct SuiteScript 2.1 equivalent. |
Scripts that use nlapiYieldScript() or nlapiSetRecoveryPoint() usually cannot be converted line by line. These functions exist to keep long-running SuiteScript 1.0 scheduled scripts within governance limits, and SuiteScript 2.1 scheduled scripts have no equivalent. In most cases, the script needs to be redesigned as a Map/Reduce script, which splits the work into stages and yields automatically. For simpler workloads, a scheduled script can instead check its remaining governance with runtime.getCurrentScript().getRemainingUsage() and resubmit itself using task.create(). Either way, this is a design change, so these scripts should be identified and scoped early in migration planning.
Oracle maintains a dedicated reference for SuiteScript 1.0 APIs that do not map directly to SuiteScript 2.1. You must consult it whenever a legacy function is missing from the direct mapping or its replacement is unclear.
Code Example: Converting nlapiLoadRecord() to SuiteScript 2.1
A legacy script may load a customer record, read its email address, and log the result.
SuiteScript 1.0
var customer = nlapiLoadRecord('customer', 123);
var email = customer.getFieldValue('email');
nlapiLogExecution('DEBUG', 'Customer Email', email);
SuiteScript 2.1
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
*/
define(['N/record', 'N/log'], (record, log) => {
const execute = () => {
const customer = record.load({
type: record.Type.CUSTOMER,
id: 123
});
const email = customer.getValue({
fieldId: 'email'
});
log.debug({
title: 'Customer Email',
details: email
});
};
return { execute };
});
This example illustrates the module-based approach, record loading, field access, and logging. The script type and entry point must match the actual purpose of your script. The sample also assumes that customer record ID 123 exists and that the script has permission to access it.
The code is not a complete migration recipe for every script that uses nlapiLoadRecord(). A production conversion must preserve the original execution context, permissions, error handling, and downstream behavior.
Code Example: Converting nlapiSearchRecord() to SuiteScript 2.1
A legacy script might search customer records using a field filter and retrieve selected columns. In SuiteScript 2.1, the search definition and result retrieval use the N/search module.
SuiteScript 1.0
var results = nlapiSearchRecord(
'customer',
null,
[
new nlobjSearchFilter('isinactive', null, 'is', 'F')
],
[
new nlobjSearchColumn('entityid'),
new nlobjSearchColumn('email')
]
);
// nlapiSearchRecord() returns null when no records match
if (results) {
for (var i = 0; i < results.length; i++) {
nlapiLogExecution(
'DEBUG',
'Customer',
'Name: ' + results[i].getValue('entityid') +
', Email: ' + results[i].getValue('email')
);
}
}
SuiteScript 2.1
/**
* @NApiVersion 2.1
* @NScriptType ScheduledScript
*/
define(['N/search', 'N/log'], (search, log) => {
const execute = () => {
const customerSearch = search.create({
type: search.Type.CUSTOMER,
filters: [
['isinactive', 'is', 'F']
],
columns: [
'entityid',
'email'
]
});
customerSearch.run().each((result) => {
log.debug({
title: 'Customer',
details: {
name: result.getValue({
name: 'entityid'
}),
email: result.getValue({
name: 'email'
})
}
});
return true;
});
};
return { execute };
});
This example demonstrates a basic search conversion. The two versions do not handle results the same way. In SuiteScript 1.0, nlapiSearchRecord() returns at most 1,000 results and returns null when nothing matches, so legacy code usually checks for null before looping. In SuiteScript 2.1, ResultSet.each() iterates through up to 4,000 results, and ResultSet.getRange() returns up to 1,000 results per call; an empty search simply returns no results, so the null check is no longer needed. For larger result sets, use search.runPaged() and process the results page by page. Because the 2.1 version can process more results than the original, confirm whether the legacy script relied on the 1,000-result cap. The original script’s filters, joins, sorting, summary columns, and expected result volume must also be preserved.
Common Conversion Errors to Check
A function-by-function map is useful, but it does not cover every behavioral difference between SuiteScript 1.0 and SuiteScript 2.1. These issues deserve specific attention during code review.
| Conversion issue | Why it causes problems | What to review |
|---|---|---|
| Incorrect module | The replacement method belongs to a different module than expected | Confirm the official API map and module reference. |
| One-based vs. zero-based indexing | A script can read or update the wrong sublist line | Review loops, line selection, and line-level operations. |
| Method vs. property | Some legacy getters map to properties, not functions | Check the mapping notes before writing the replacement. |
| Different search result handling | Search execution and result iteration may work differently | Verify limits, pagination, filters, sorting, and returned values. |
| Record mode differences | Standard and dynamic record operations do not behave identically | Confirm whether the original process relies on dynamic-mode behavior. |
| Subrecord differences | SuiteScript 2.1 handles subrecords differently | Review the parent record, subrecord access, and save behavior. |
| Logging differences | The new logging methods and deployment log levels affect output | Select the appropriate log method and confirm deployment settings. |
| Missing direct equivalent | A legacy API may require a different implementation | Review Oracle’s non-direct mapping reference before converting. |
How to Use This API Map During Migration
The mapping tables are most useful when each legacy API is reviewed in the context of the script that uses it. The same function can serve different purposes in different scripts, and the correct replacement depends on those requirements.
A practical conversion review should cover these steps:
- Identify the legacy API. Record each
nlapifunction andnlobjobject used by the script. - Confirm the replacement. Check the relevant API map and module documentation instead of assuming that the new method has the same signature.
- Review behavior differences. Check indexing, record mode, search result handling, execution context, and other differences relevant to the script.
- Update dependencies and entry points. Confirm that the converted script uses the correct modules and a supported entry point for its script type.
- Test the business outcome. Validate the resulting records, searches, integrations, and downstream workflows in a sandbox before production deployment.
Oracle also publishes sample SuiteScript 1.0 to 2.1 conversions, covering several script types, including client scripts, scheduled scripts, Suitelets, RESTlets, user event scripts, workflow action scripts, and custom modules.
Final Considerations
The correct SuiteScript 1.0 to 2.1 mapping depends on the function or object, its module, and the behavior the original code needs to preserve. A direct API replacement is only one part of conversion. Search logic, record mode, indexing, execution context, subrecord handling, and error behavior can all affect the result.
Use the tables in this guide as a practical starting point, then confirm each replacement against Oracle’s official SuiteScript 1.0 to 2.1 API map. For scripts with complex dependencies or business-critical behavior, a technical review and sandbox regression testing are essential before production deployment.
FAQs
What is the SuiteScript 2.1 equivalent of nlapiLoadRecord()?
The SuiteScript 2.1 equivalent of nlapiLoadRecord() is record.load({type, id}), and {recordmode:'dynamic'} becomes isDynamic: true. In SuiteScript 2.1, the function is replaced by the record.load() method in the N/record module.
What is the SuiteScript 2.1 equivalent of nlapiSearchRecord()?
The equivalent depends on the original search logic. A new search uses search.create() in N/search, while an existing saved search uses search.load(). The conversion also needs the correct search execution and result-handling logic.
What replaces nlobjRecord in SuiteScript 2.1?
The legacy nlobjRecord maps to record.Record or currentRecord.CurrentRecord, depending on the context. Server-side record operations commonly use N/record, while client scripts use N/currentRecord to access the active UI record.
Do all nlapi and nlobj APIs have SuiteScript 2.1 equivalents?
No. Some APIs have direct equivalents, some map to multiple methods or properties, and others require a different implementation. Oracle’s official API map and non-direct mapping reference identify these cases.
Can SuiteScript 1.0 APIs be called from SuiteScript 2.1?
No. NetSuite does not support calling SuiteScript 1.0 APIs directly from SuiteScript 2.1 scripts. The legacy API calls need to be converted to supported SuiteScript 2.1 functionality or redesigned where a direct equivalent does not exist.
Is adding @NApiVersion 2.1 to a SuiteScript 1.0 script enough to migrate a script?
No. Changing the version annotation does not convert legacy global functions, update object methods, add module dependencies, or resolve behavioral differences. A SuiteScript 1.0 migration requires code conversion and testing.