Skip to main content
Version: 4.8.0

Now.ID

Now.ID['key-name'] gives a Fluent record a stable, human-readable identity. Use it to assign the $id property on any API that accepts one — the build system maps the key to a real sys_id and keeps it stable across builds.

Note: Now is a global available in every .now.ts file — it does not need to be imported. Do not add Now to any import { ... } from '@servicenow/sdk/core' line; use Now.ID[...] directly.

Basic usage

import { BusinessRule } from '@servicenow/sdk/core'

BusinessRule({
$id: Now.ID['validate-priority-on-insert'],
name: 'Validate priority on insert',
table: 'incident',
when: 'before',
action: 'insert',
script: Now.include('./validate-priority.js'),
})

The first time you build, the key 'validate-priority-on-insert' is added to your project's keys.ts file with a newly generated sys_id. Every build after that uses the same sys_id — so the record is updated in place, not duplicated.

How the build system handles keys

First build — key is new

BusinessRule({
$id: Now.ID['my-new-rule'], // key doesn't exist yet in keys.ts
// ...
})

The build system:

  1. Sees 'my-new-rule' is not in keys.ts
  2. Generates a new sys_id
  3. Adds the entry to keys.ts
  4. Uses that sys_id in the XML output

Subsequent builds — key exists

BusinessRule({
$id: Now.ID['my-new-rule'], // key now exists in keys.ts
// ...
})

The build system:

  1. Looks up 'my-new-rule' in keys.ts
  2. Finds the existing sys_id
  3. Uses the same sys_id — the record is updated, not duplicated

When to use $id

APIs where $id is the right choice

Use $id: Now.ID['...'] on any top-level record you want to identify by name:

import { Acl, BusinessRule, ScriptInclude } from '@servicenow/sdk/core'

Acl({
$id: Now.ID['incident-read-acl'],
// ...
})

BusinessRule({
$id: Now.ID['business-rule-example'],
// ...
})

ScriptInclude({
$id: Now.ID['script-include-example'],
// ...
})

When $id is optional

$id is technically optional on some APIs. However, omitting it means the record is identified only by its coalesce keys (typically name). If you ever rename the record, a new record is created and the old one is orphaned. Always provide $id on APIs that support it.

Nested records

Some APIs have child records that also accept $id. Assign one whenever you want a stable reference to a nested item:

import { SPMenu } from '@servicenow/sdk/core'

SPMenu({
$id: Now.ID['main-nav-menu'],
title: 'Main Navigation',
items: [
{
$id: Now.ID['main-nav-home'],
type: 'page',
label: 'Home',
page: 'homepage',
},
{
$id: Now.ID['main-nav-tickets'],
type: 'page',
label: 'My Tickets',
page: 'ticket_list',
},
],
})

Choosing key names

Key names are strings — choose something that is:

  • Descriptive'validate-priority-on-insert' is better than '1' or 'vp'
  • Scoped to the record — include the table or feature area when helpful: 'incident-read-acl', 'main-nav-menu'
  • Stable — renaming a key creates a new record; the old one is orphaned unless cleaned up manually

Any string is valid. Kebab-case is conventional but not required.

IDE autocomplete

Once a key exists in your project's keys.ts, your IDE autocompletes it when you type Now.ID['. Keys that do not exist yet are also accepted — the build creates them on the next run.

Referencing records across files

Now.ID is only for assigning identity — it is not a reference mechanism. To reference a Fluent record from another file, use the exported variable directly, or its .$id property when only the identifier is needed.

Pass the variable directly

Export the API call result and import it where needed. This is the standard pattern:

// example.now.ts
import { Record } from '@servicenow/sdk/core'

export const recordExample = Record({
$id: Now.ID['record-example-1'],
table: 'x_myapp_table',
data: {
name: 'Example Record'
}
})
// example-two.now.ts
import { Record } from '@servicenow/sdk/core'
import { recordExample } from './example.now'

Record({
$id: Now.ID['record-example-2'],
table: 'x_myapp_othertable',
data: {
reference_field: recordExample
}
})

Use variable.$id when only the identifier is needed

If an API only accepts a string for an identifier rather than the full record object, pass variable.$id:

import { Acl } from '@servicenow/sdk/core'
import { AdminRole } from './roles.now'

Acl({
$id: Now.ID['my-acl'],
table: 'x_myapp_table',
operation: 'read',
roles: [AdminRole.$id],
})

What not to do

Don't use Now.ID outside of key creation for a record

Now.ID['key'] is only for generating IDs, never for referencing them elsewhere in fluent

import { Record } from '@servicenow/sdk/core'

// ✅ CORRECT — $id resolves to a sys_id
export const vendorAcme = Record({
$id: Now.ID['vendor-acme'],
table: 'x_myapp_vendor',
data: { name: 'Acme Corp' },
})

// ✅ CORRECT — pass the exported variable to reference a same-app record
Record({
$id: Now.ID['contract-1'],
table: 'x_myapp_contract',
data: {
vendor: vendorAcme, // resolves correctly
},
})

// ❌ WRONG — Now.ID in a data field writes the literal string, not a sys_id
Record({
$id: Now.ID['contract-1'],
table: 'x_myapp_contract',
data: {
vendor: Now.ID['vendor-acme'], // writes "vendor-acme" to the DB
},
})

Don't use raw sys_ids for same-app records

Hardcoded sys_ids only work in one environment. If a record is defined in your project, reference it with the exported variable rather than copying the sys_id from an instance.

// ❌ WRONG — hardcoded sys_id breaks in other environments
data: {
flow: 'a1b2c3d4e5f67890abcdef1234567890',
}

// ✅ CORRECT — cross-environment reference
data: {
flow: myFlow, // exported variable from your project
}

Decision table

ScenarioPattern
Give a record a stable identity$id: Now.ID['descriptive-name']
Reference a record from the same filePass the exported variable directly
Reference a record from another .now.ts fileimport { MyRecord } from './other.now', then pass MyRecord or MyRecord.$id
Reference a platform record by coalesce keysNow.ref('table', { field: 'value' })
Reference a platform record by sys_idraw sys_id string

Further reading