🎯 N/runtime Overview
The N/runtime module provides information about the execution environment. It answers key questions:
- Who is running this script? → getCurrentUser()
- What script is this? → getCurrentScript()
- How much governance remains? → getRemainingUsage()
- What parameters were configured? → getParameter()
- Which features are enabled? → isFeatureInEffect()
👤 Getting Current User
Know who's running your script for assignments, logging, and personalization:
const runtime = require('N/runtime');
const currentUser = runtime.getCurrentUser();
log.audit('User Info', {
id: currentUser.id, // Internal ID (e.g., 207)
name: currentUser.name, // Display name (e.g., "John Smith")
email: currentUser.email, // Email address
role: currentUser.role, // Current role ID
roleId: currentUser.roleId, // Same as role
roleCenter: currentUser.roleCenter, // Role center type
department: currentUser.department, // Department ID
location: currentUser.location, // Location ID
subsidiary: currentUser.subsidiary // Subsidiary ID
});
📧 Example: New Employee Welcome Call
When a new employee is created, automatically create a phone call task assigned to the current user (likely HR).
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/runtime', 'N/record'], (runtime, record) => {
const afterSubmit = (context) => {
if (context.type !== context.UserEventType.CREATE) return;
const employee = context.newRecord;
const firstName = employee.getValue('firstname');
const lastName = employee.getValue('lastname');
const phoneNumber = employee.getValue('phone');
// Create phone call assigned to whoever created the employee
const phoneCall = record.create({ type: record.Type.PHONE_CALL });
phoneCall.setValue({
fieldId: 'assigned',
value: runtime.getCurrentUser().id // Assign to current user
});
phoneCall.setValue({
fieldId: 'title',
value: `Welcome call: ${firstName} ${lastName}`
});
phoneCall.setValue({
fieldId: 'message',
value: `Welcome call for new employee at ${phoneNumber}.`
});
const recordId = phoneCall.save();
log.debug('Phone Call Created', recordId);
};
return { afterSubmit };
});
⚙️ Script Parameters
Script parameters let administrators configure scripts without changing code. Define them in the script record, then read at runtime:
const runtime = require('N/runtime');
const script = runtime.getCurrentScript();
// Read a script parameter (defined in script record)
const recipientId = script.getParameter({
name: 'custscript_notif_recipient' // Parameter ID
});
const approvalThreshold = script.getParameter({
name: 'custscript_approval_limit'
});
log.audit('Parameters', { recipientId, approvalThreshold });
💡 Why Use Parameters?
Instead of hardcoding values like email recipients or thresholds, use script parameters. Administrators can change them in the deployment without touching code.
📧 Example: Configurable Notification Recipient
Send a notification when records are created, but let administrators configure who receives it via script parameter.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/runtime', 'N/email'], (runtime, email) => {
const afterSubmit = (context) => {
try {
if (context.type !== context.UserEventType.CREATE) return;
// Get recipient from script parameter (not hardcoded!)
const recipientId = runtime.getCurrentScript().getParameter({
name: 'custscript_notif_recipient'
});
email.send({
author: runtime.getCurrentUser().id,
recipients: recipientId,
subject: `New ${context.newRecord.type} record created!`,
body: `${runtime.getCurrentUser().name} created a new
${context.newRecord.type} record for
${context.newRecord.getValue('entityid')}.`
});
} catch (e) {
log.error({ title: e.name, details: e.message });
}
};
return { afterSubmit };
});
🔓 Feature Detection
Check if a NetSuite feature is enabled before using it. This prevents errors when scripts run in accounts with different configurations:
const runtime = require('N/runtime');
// Check if Opportunities feature is enabled
const opportunitiesEnabled = runtime.isFeatureInEffect({
feature: 'OPPORTUNITIES'
});
// Check other common features
const multiCurrency = runtime.isFeatureInEffect({ feature: 'MULTICURRENCY' });
const advancedBilling = runtime.isFeatureInEffect({ feature: 'ADVANCEDBILLING' });
const serializedInventory = runtime.isFeatureInEffect({ feature: 'SERIALIZEDINVENTORY' });
🔒 Example: Feature-Gated Record Creation
Only create an Opportunity if the feature is enabled in the account.
require(['N/record', 'N/runtime'], (record, runtime) => {
const opportunitiesEnabled = runtime.isFeatureInEffect({
feature: 'OPPORTUNITIES'
});
if (opportunitiesEnabled) {
const newOpport = record.create({
type: record.Type.OPPORTUNITY
});
newOpport.setValue({ fieldId: 'title', value: 'Office chairs hire' });
newOpport.setValue({ fieldId: 'entity', value: 325 });
newOpport.setSublistValue({
sublistId: 'item',
fieldId: 'item',
line: 0,
value: 14
});
const recordId = newOpport.save();
log.debug('Opportunity saved!', recordId);
} else {
log.debug('Skipped', 'Opportunities feature is not enabled.');
}
});
⚠️ Common Feature IDs
OPPORTUNITIES, MULTICURRENCY, MULTISUBSIDIARY, ADVANCEDBILLING, SERIALIZEDINVENTORY, LOTTRACKING, CUSTOMRECORDS. Find more in NetSuite Help under "Feature IDs".
⚡ Governance Monitoring
Governance is NetSuite's way of limiting API calls. Every script has a governance budget—exceed it, and your script stops.
Governance Limits by Script Type
| Script Type | Units | Notes |
|---|---|---|
| Client Script | 1,000 | Runs in browser |
| User Event | 1,000 | Per record action |
| Suitelet | 1,000 | Per page request |
| Scheduled Script | 10,000 | Can reschedule itself |
| Map/Reduce (getInputData) | 10,000 | Data gathering stage |
| Map/Reduce (map) | 1,000 | Per map invocation |
| Map/Reduce (reduce) | 5,000 | Per reduce invocation |
| Map/Reduce (summarize) | 10,000 | Final summary stage |
Monitoring Remaining Units
const runtime = require('N/runtime');
function processRecords() {
const script = runtime.getCurrentScript();
// Check before expensive operations
const remaining = script.getRemainingUsage();
log.audit('Governance', 'Remaining: ' + remaining);
if (remaining < 100) {
log.audit('Governance', 'Low on units, stopping early');
return; // Exit gracefully before hitting limit
}
// Continue processing...
}
Common Operation Costs
| Operation | Units |
|---|---|
| record.load() | 10 |
| record.save() / record.create() | 10 |
| record.submitFields() | 10 |
| search.create().run() | 10 |
| query.runSuiteQL() | 10 |
| email.send() | 10 |
| http.request() | 10 |
| file.load() | 10 |
💡 Key Insight
Most operations cost 10 units. With 1,000 units, you can do ~100 operations. Plan accordingly!
🚀 Optimization Strategies
1. Use Searches Over Multiple Loads
// BAD: 100 units for 10 records
for (let id of recordIds) {
const rec = record.load({ type: 'customer', id: id }); // 10 units each
}
// GOOD: 10 units for all records
const customerSearch = search.create({
type: 'customer',
filters: [['internalid', 'anyof', recordIds]],
columns: ['companyname', 'email']
}).run(); // 10 units total
2. Use submitFields for Updates
// BAD: 20 units (load + save)
const rec = record.load({ type: 'customer', id: 123 });
rec.setValue('email', 'new@example.com');
rec.save();
// GOOD: 10 units
record.submitFields({
type: 'customer',
id: 123,
values: { email: 'new@example.com' }
});
3. Choose Map/Reduce for Large Jobs
Map/Reduce scripts get fresh governance at each stage and can process unlimited records across multiple invocations.
✅ Map/Reduce Advantage
Each stage gets its own governance pool. If map runs out, it yields and resumes later with fresh units.
🌐 Environment Detection
Detect which environment (production vs sandbox) you're running in:
const runtime = require('N/runtime');
// Get account ID
const accountId = runtime.accountId; // e.g., "1234567" or "1234567_SB1"
// Check if sandbox
const isSandbox = accountId.toLowerCase().includes('_sb');
// Get environment type
const envType = runtime.envType; // PRODUCTION, SANDBOX, BETA, INTERNAL
if (runtime.envType === runtime.EnvType.SANDBOX) {
log.debug('Environment', 'Running in Sandbox');
}
📖 Finding This in the Docs
To look up N/runtime:
- Go to docs.oracle.com → SuiteScript 2.x Modules
- Click on N/runtime Module
- Review User, Script, and Session objects
Key pages to bookmark:
- runtime.getCurrentUser() → User object properties
- runtime.getCurrentScript() → Script object, getParameter(), getRemainingUsage()
- runtime.isFeatureInEffect() → feature detection
- runtime.envType → environment detection
- SuiteScript 2.x API Governance → units per operation table
🎯 Key Takeaways
- runtime.getCurrentUser() returns id, name, email, role, department, location
- runtime.getCurrentScript().getParameter() reads deployment-configured values
- runtime.isFeatureInEffect() checks if account features are enabled
- runtime.getCurrentScript().getRemainingUsage() monitors governance
- Most operations cost 10 units; script types have 1,000-10,000 unit budgets
- Use script parameters instead of hardcoding values—makes scripts configurable
- Check features before using them to prevent errors in different accounts
- Monitor governance and exit gracefully before hitting limits