π§ Introduction
NetSuite offers two powerful ways to automate record logic:
- SuiteScript User Event (UE) scripts β code that runs on record load/submit.
- Workflow Actions (WFA) β no/low-code actions inside SuiteFlow states and transitions.
Both can update fields, send emails, and enforce rules β but they shine in different situations. This guide shows how to choose the right tool, with checklists, examples, and hybrid patterns.
TL;DR Decision Matrix
| Scenario | Best Choice | Why |
|---|---|---|
| Simple field updates, emails, approvals | Workflow Action | Visual, quick to maintain |
| Complex validation, multi-step calculations | User Event | Full JS control & libraries |
| Needs external module reuse/shared utils | User Event | Modular code, unit-testable |
| Non-technical admin will maintain | Workflow Action | Clicks over code |
| Requires external API/crypto/advanced search | User Event | HTTPS, Crypto, Search APIs |
| Must run at specific timing (before submit) | User Event (beforeSubmit/afterSubmit) | Precise lifecycle hooks |
| Multi-entity routing with dynamic logic | Hybrid (WFA + WFA Script) | SuiteFlow UX + code power |
| Strict governance/perf tuning needed | User Event | Fine-grained control & caching |
π§© What Is a User Event Script?
User Event scripts execute during a recordβs lifecycle:
beforeLoadβ modify form/UI, add buttons, set default valuesbeforeSubmitβ validations, normalize data before saveafterSubmitβ post-save side effects (create related records, queue tasks)
Strengths
- Full access to SuiteScript modules (
record,search,runtime,https,crypto,task, etc.) - Reusable modules, robust error handling, version control
- Precise timing: run before the record is saved or after itβs committed
Limitations
- Requires developer maintenance & deployment
- Can be overkill for simple, visual processes
Micro-Example (2.1, beforeSubmit)
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/record','N/error'], (record, error) => {
const beforeSubmit = (ctx) => {
const rec = ctx.newRecord;
if (!rec.getValue('entity')) {
throw error.create({name:'MISSING_CUSTOMER',message:'Customer is required.'});
}
if (rec.getValue('total') > 25000) {
rec.setValue('custbody_requires_cfo', true);
}
};
return { beforeSubmit };
});
π§© What Is a Workflow Action?
Workflow Actions (a.k.a. Custom Workflow Action Scripts or built-in actions) run inside SuiteFlow states/transitions. You can:
- Set field values, send emails, create records
- Gate transitions with conditions
- Add Approve/Reject buttons
Strengths
- Visual, fast to build/adjust
- Ideal for approvals & role-based routing
- Easy for admins to maintain
Limitations
- Limited for heavy logic & integrations (though Custom Workflow Action Script helps)
- Governance & debugging visibility can be less granular
Micro-Example (Custom Workflow Action Script)
/**
* @NApiVersion 2.1
* @NScriptType WorkflowActionScript
*/
define(['N/search'], (search) => {
const onAction = (ctx) => {
const rec = ctx.newRecord;
// Flag approval if open balance > 0
const openBal = search.lookupFields({
type: 'customer',
id: rec.getValue('entity'),
columns: ['balance']
}).balance || 0;
rec.setValue('custbody_hold_for_review', openBal > 0);
return `Open Balance = ${openBal}`;
};
return { onAction };
});
π§ Timing & Lifecycle Differences
| Hook | User Event | Workflow Action |
|---|---|---|
| Before UI render | beforeLoad | (N/A) |
| Before save (hard validations) | beforeSubmit | State entry can validate but post-UI |
| After save (side effects) | afterSubmit | State/transition actions (post-save) |
| Button clicks | Add via beforeLoad | Add buttons in SuiteFlow state |
Need hard stop before the record is saved? Prefer User Event
beforeSubmit.
βοΈ Governance & Performance
- UE: Finer control; use
lookupFields, caching (N/cache), and batch post-save logic viatask(Map/Reduce). - WFA: Keep actions light; offload heavy logic to a Custom Workflow Action Script or call a RESTlet/Map-Reduce indirectly.
Tip: If an action regularly exceeds ~500β700 units, consider moving the heavy logic to UE afterSubmit or a background task.
π§ͺ Debugging & Maintainability
| Area | User Event | Workflow Action |
|---|---|---|
| Logs | Script Execution Log + custom records | Workflow History + Action return text |
| Versioning | Strong with SDF/Git | Version by workflow revisions & XML export |
| Ownership | Dev team | Admins/functional, plus dev for custom actions |
β Common Use Cases β Side-by-Side
| Use Case | Pick | Notes |
|---|---|---|
| Approval routing by amount/department | Workflow | Visual, buttons, emails |
| Strict field validation before save | UE (beforeSubmit) | Block save reliably |
| Create related records after save | UE (afterSubmit) | Safer post-commit |
| Add custom UI buttons/menus | UE (beforeLoad) | Full control |
| Conditional emails on status change | Workflow or UE afterSubmit | Workflow for simple, UE for dynamic data pulls |
| Complex calculations / multi-search | UE | Performance & libraries |
| Non-dev team must tune rules | Workflow | Easy maintenance |
π Hybrid Pattern (Best of Both)
- Workflow handles states, transitions, emails, and buttons.
- Custom Workflow Action Script does light logic (set flags, lookup IDs).
- UE afterSubmit (or Map/Reduce) consumes flags and performs heavy lifting (mass updates, complex calculations, report generation).
Why: Visual business control + scalable code where it matters.
π§° Practical Examples
A) Auto-Approval Under Threshold (Workflow only)
- State: Pending β Approved
- Transition condition:
{total} < 5000β Auto transition - Action: Set
custbody_approved_by = currentUser
B) Strict Required Field (User Event)
beforeSubmit: if{custbody_shipmethod}empty, throw user error- Guarantees no record saves without ship method
C) Manager/CFO Routing (Hybrid)
- Workflow calculates path, sets
custbody_requires_cfo - UE
afterSubmitlogs an audit record & schedules an email summary or downstream process
π§© Checklist: Choose the Right Tool
- Is it pre-save validation? β User Event (beforeSubmit)
- Is it approval/UI flow with multiple states & emails? β Workflow
- Does business need to edit rules without devs? β Workflow
- Is logic complex, reusable, or integration-heavy? β User Event / Custom Module
- Do you need both clarity and power? β Hybrid (Workflow + UE/WFA Script)
π οΈ Setup & Deployment Tips
- Naming:
- UE:
UE_<Record>_<Purpose>_vX.Y.js - Workflow:
WF_<Record>_<Purpose>_vX.Y - WFA Script:
WFA_<Purpose>_vX.Y.js
- UE:
- SDF: Export both scripts and workflow XML for Git versioning.
- Testing: Cover create, edit, copy, CSV import, web services.
- Auditing: Log to a small Custom Record when key rules hit (flag, who, when).
π§― Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| Workflow buttons donβt show | State not on View / audience mismatch | Enable βOn Viewβ, check roles |
| Validation didnβt block save | Put logic in WFA post-save | Move to UE beforeSubmit |
| Double emails | UE and Workflow both sending | Centralize in one layer; use flags |
| Slow saves | Heavy searches in WFA/UE | Use lookupFields, cache, or defer to Map/Reduce |
π Related Tutorials
- π SuiteFlow Basics & Approval Workflows
- π Custom Workflow Actions
- π Advanced Approval Workflows
β FAQ
Q1. Can a record run multiple workflows and UEs?
Yes. NetSuite runs all applicable workflows and deployments; design to avoid conflicts.
Q2. Where should I send emails?
Workflow for simple notifications; UE afterSubmit for dynamic, data-rich, or attachment-heavy emails.
Q3. Can I simulate pre-save with Workflow?
Not reliably. Use UE beforeSubmit for guaranteed βblock saveβ behavior.
Q4. Can WFA call external APIs?
Indirectly via a Custom Workflow Action Script using N/https, but keep it light; push heavy work to UE/Map-Reduce.
π§ Summary
- Use Workflow Actions for visual approvals, simple automation, and admin-friendly rules.
- Use User Event scripts for strict pre-save validation, complex logic, integrations, and performance control.
- For larger processes, adopt a hybrid: Workflow for orchestration + UE/WFA Script for heavy logic.
Leave a Reply