Scheduled Script Guide
Create ServiceNow Scheduled Script Executions (sysauto_script) to run server-side logic on a time-based schedule. This guide covers all 11 frequency types, script file patterns, timezone handling, conditional execution, business calendar integration, and best practices.
When to Use
- Running server-side logic at a fixed time every day, week, month, or year
- Recurring background maintenance tasks (data cleanup, archiving, cache refresh)
- Periodic data synchronization with external systems
- Generating scheduled reports or summary notifications
- Executing a script exactly once at a future date/time
- Running a script manually on-demand (no automated trigger)
- Scheduling jobs that align with business calendar entries
- Repeating at a custom interval (e.g., every 4 hours, every 30 minutes)
Do NOT Use For
- Structured bulk data imports (CSV, LDAP, REST sources with transform maps)
- Multi-step orchestrations with branching conditions and discrete actions on a timer
Core Principles
- Choose
frequencyfirst: This determines which companion fields are required and which are ignored. - Use
Now.includefor scripts: The ScheduledScript API only accepts strings, so reference an external.jsfile withNow.include('./path-to-file.js'). The script must use an IIFE:(function() { ... })();. timeZone: All times inexecutionStart,executionEnd, andexecutionTimeare interpreted in thetimeZoneyou set. Use'floating'to always match the platform's current system timezone. Avoid setting unless explicitly specified by the user.executionIntervalis exclusive toperiodically: Setting it on any other frequency is a build error.daysOfWeekis required forweekly: Omitting it is a build error.businessCalendaris required for calendar types: Bothbusiness_calendar_startandbusiness_calendar_endrequire it.executionEndmust allow at least one execution: For recurring jobs, must be at least one full interval afterexecutionStart.
Quick Decision Guide
| User says | Use frequency | Required extra fields |
|---|---|---|
| "every day at X", "nightly", "daily" | daily | executionTime |
| "every Monday", "on Tuesdays and Fridays" | weekly | daysOfWeek (mandatory; array of lowercase names) |
| "first of the month", "every month on day X" | monthly | dayOfMonth (1-31; 31 = month-end) |
| "every N hours/minutes", "periodically" | periodically | executionInterval (mandatory), executionStart recommended |
| "once", "one-time", "migration" | once | executionStart |
| "manually", "on demand" | on_demand | (none) |
| "every year on [month] [day]" | day_and_month_in_year | month (1-12), dayOfMonth (1-31) |
| "second Monday of every month" | week_in_month | weekInMonth (1-6), dayOfWeek |
| "third Tuesday of March every year" | day_week_month_year | dayOfWeek, weekInMonth, month |
| "when business period starts" | business_calendar_start | businessCalendar |
| "when business period ends" | business_calendar_end | businessCalendar |
Do I need executionTime?
- Recommended for:
daily,weekly,monthly,day_and_month_in_year,week_in_month,day_week_month_year - Not applicable:
periodically(usesexecutionInterval),once(usesexecutionStart),on_demand
Do I need executionStart?
- Recommended:
periodically,once - Optional: all other types (use to define when the first execution is eligible)
- If you do not have date/time context from the user, omit it -- Fluent will auto-populate with the current date/time during build.
API Reference
For the full property reference, see the scheduledscript-api topic.
Valid Frequency Values
'daily', 'weekly', 'monthly', 'periodically', 'once', 'on_demand', 'day_and_month_in_year', 'day_week_month_year', 'week_in_month', 'business_calendar_start', 'business_calendar_end'
Run Type Details
daily-- Runs once per day atexecutionTime.weekly-- Runs on specific weekdays. RequiresdaysOfWeek(array).monthly-- Runs on a fixed day. RequiresdayOfMonth. If the day does not exist in a month (e.g., 31 in February), it runs on the last day instead. SodayOfMonth: 31effectively becomes a month-end job.periodically-- Repeats at a fixed interval. RequiresexecutionInterval. Avoid seconds or single-digit minutes for performance. If a run is still executing when the next fires, the platform skips that trigger silently.once-- Runs once atexecutionStart, then stops.on_demand-- Never runs automatically; triggered manually.day_and_month_in_year-- Runs annually on a fixed date. Requiresmonth+dayOfMonth.week_in_month-- Runs on a specific week ordinal. RequiresweekInMonth+dayOfWeek.day_week_month_year-- Runs on a specific weekday in a specific week in a specific month each year.business_calendar_start/business_calendar_end-- Fires when calendar entries begin/end. RequiresbusinessCalendar.
Script File Pattern
The ScheduledScript API only accepts strings for its script property and should use Now.include to import the javascript code, see the now-include topic for more information
The script file must use an IIFE (Immediately Invoked Function Expression):
(function () {
// your logic here
})();
Reference it from the script field:
import { ScheduledScript } from '@servicenow/sdk/core'
ScheduledScript({
$id: Now.ID['my-job'],
name: 'My Job',
script: Now.include('../../server/scheduled-scripts/my-job.js'),
frequency: 'daily',
executionTime: Time({ hours: 2, minutes: 0 }),
})
Note: Unlike BusinessRule and ScriptAction, the ScheduledScript API does not accept function types. Module imports will produce a TypeScript error. Use
Now.include()or inline strings.
Script Best Practices
- Always use an IIFE wrapper
- Add try-catch blocks for error handling
- Use
gs.info()for success,gs.error()for failures,gs.debug()for tracing - Keep scripts focused -- one task per scheduled script
- Use
setLimit()when processing large datasets - Return early on failed preconditions
- Add JSDoc comments explaining the script's purpose
Timezone Handling
timeZone-- Controls howexecutionStart,executionEnd, andexecutionTimeare interpreted. Platform stores UTC internally.'floating'-- Always uses the platform's currently configured system timezone.userTimeZone-- Controls timezone forGlideDateTimecalculations inside the script. Defaults to therunAsuser's profile timezone.
Conditional Execution
Set conditional: true and provide a condition script for dynamic per-cycle skipping:
ScheduledScript({
$id: Now.ID["conditional-job"],
name: "Weekday-Only Sync",
script: Now.include("./conditional-job.server.js"),
frequency: "daily",
executionTime: Time({ hours: 6, minutes: 30 }),
conditional: true,
condition: `
var day = gs.getDayOfWeekLocalTime();
day >= 2 && day <= 6; // Monday (2) through Friday (6)
`
});
Common use cases: weekend/holiday checks, data-driven execution (system property flags), time-specific logic.
Protection
protectionPolicy: 'read'-- Others can view but not modifyprotectionPolicy: 'protected'-- Others cannot view or modify- Omit to allow full customization
Business Calendar Best Practices
- Always reference business calendar entries by sys_id from the
business_calendartable - The platform provides standard entries for weeks, months, quarters, and years
- If the user provides a specific calendar name or sys_id, use that instead
Examples
Basic Daily Job
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["close-resolved-incidents"],
name: "Close Resolved Incidents",
script: Now.include("./close-resolved-incidents.server.js"),
frequency: "daily",
executionTime: Time({ hours: 2, minutes: 0 }),
runAs: "6816f79cc0a8016401c5a33be04be441",
});
Script file (close-resolved-incidents.server.js):
(function () {
var gr = new GlideRecord("incident");
gr.addEncodedQuery("state=6^sys_updated_onRELATIVELT@dayofweek@ago@30");
gr.query();
var count = 0;
while (gr.next()) {
gr.state = 7;
gr.update();
count++;
}
gs.info("Closed " + count + " resolved incidents older than 30 days");
})();
Weekly Job
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["weekly-sla-report"],
name: "Weekly SLA Report",
script: Now.include("./weekly-sla-report.server.js"),
frequency: "weekly",
daysOfWeek: ["monday", "friday"],
executionTime: Time({ hours: 7, minutes: 0 }),
});
Periodically (Every 4 Hours)
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["periodic-sync"],
name: "Periodic Data Sync",
script: Now.include("./periodic-sync.server.js"),
frequency: "periodically",
executionInterval: Duration({ hours: 4 }),
advanced: true,
});
One-Time Migration
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["one-time-migration"],
name: "Data Migration Script",
script: Now.include("./one-time-migration.server.js"),
frequency: "once",
executionStart: "2026-06-15 02:00:00",
});
On-Demand
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["manual-cache-refresh"],
name: "Manual Cache Refresh",
script: Now.include("./manual-cache-refresh.server.js"),
frequency: "on_demand",
});
Monthly (Last Day)
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["monthly-report"],
name: "Monthly Report Generator",
script: Now.include("./monthly-report.server.js"),
frequency: "monthly",
dayOfMonth: 31,
executionTime: Time({ hours: 23, minutes: 0 }),
});
Annual Job
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["annual-license-review"],
name: "Annual License Review",
script: Now.include("./annual-license-review.server.js"),
frequency: "day_and_month_in_year",
month: 1,
dayOfMonth: 15,
executionTime: Time({ hours: 9, minutes: 0 }),
});
Week-in-Month Job
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["second-monday-report"],
name: "Second Monday Report",
script: Now.include("./second-monday-report.server.js"),
frequency: "week_in_month",
weekInMonth: 2,
dayOfWeek: "monday",
executionTime: Time({ hours: 8, minutes: 0 }),
});
Daily with Inline Script
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["daily-notification"],
name: "Daily Morning Notification",
script: `(function() {
gs.eventQueue('x_myapp.daily.notification', null, gs.nowDateTime(), gs.getUserID());
gs.info('Daily notification sent at ' + gs.nowDateTime());
})()`,
frequency: "daily",
executionTime: Time({ hours: 9, minutes: 0 }),
});
Daily with Bounded Execution Period
import "@servicenow/sdk/global";
import { ScheduledScript } from "@servicenow/sdk/core";
ScheduledScript({
$id: Now.ID["q1-daily-report"],
name: "Q1 Daily Status Report",
script: Now.include("./q1-daily-report.server.js"),
frequency: "daily",
executionTime: Time({ hours: 8, minutes: 0 }),
executionStart: "2026-01-01 08:00:00",
executionEnd: "2026-03-31 23:59:59",
});