Skip to main content
Version: 4.6.0

Creating Workspaces Guide

Guide for creating ServiceNow Workspaces -- complete out-of-the-box solutions for managing business entities through standardized CRUD workflows. A workspace automatically generates a dashboard page, list management views, and detailed forms following ServiceNow's standard UX patterns.

When to Use

  • When creating new workspaces
  • When the user asks about workspace configuration or best practices
  • When building a full business process interface with dashboard, list management, and detail forms

What is a Workspace?

A Workspace automatically generates a complete set of pages for managing a business entity:

  • Dashboard Page: Overview dashboard with key metrics and recent activity
  • List Page: Searchable, filterable table view with bulk operations
  • Detail/Form Page: Full CRUD form with related records and actions

Instructions

Step 1: Understand the Requirement

  • Identify the required tables.
    • First, check whether they already exist on the platform.
    • If not, look for them within the project.
    • Create new tables only if they cannot be found in either location.
  • Gather details about the tables' columns.

Step 2: Configure the UX List Menu

Create a UxListMenuConfig inside list-menu.now.ts defining the navigation structure and list views.

Step 3: Configure the Workspace

Create a Workspace in workspace.now.ts:

  • Ensure you also create an ACL to secure the workspace route.
  • Associate the UX List Menu configuration to the workspace.

Step 4: Configure the Dashboard (Mandatory)

Create a Dashboard inside dashboard.now.ts:

  • Associate the dashboard to the workspace via visibilities.
  • The dashboard is mandatory for the workspace to function correctly.

Step 5: Verify Integration

  • Ensure the UxListMenuConfig is properly referenced in the workspace.
  • Verify that the workspace is referenced in dashboard visibilities.
  • Confirm ACL field matches workspace path pattern: {path}.*
  • Check that all roles are properly defined and referenced.

Step 6: Build, Install, and Provide Summary

After building and installing, read src/fluent/generated/keys.ts to extract the actual sys_id from sys_ux_page_registry for the workspace. Provide the user with:

  • A clickable URL to access the workspace: /now/{path}/{landingPath}
  • A clickable URL to edit in UI Builder: /now/builder/ui/experience/{workspace_sys_id}

File Organization

src/
fluent/
workspaces/
incident-tracker/
workspace.now.ts
list-menu.now.ts
dashboard.now.ts

Workspace URL Structure

/now/{path}/{landingPath}

If path: 'my-example', the URL is /now/my-example/home (landingPath defaults to home).


Workspace API Reference

Workspace Properties

For the full property reference, see the workspace-api topic.

Workspace Example

import { Workspace, UxListMenuConfig, Acl, Applicability, Role } from '@servicenow/sdk/core';

// 1. Define roles
const userRole = Role({
$id: Now.ID['asset_workspace_user_role'],
name: 'x_snc_asset.user',
containsRoles: ['canvas_user'],
});

// 2. Define applicability
const assetApplicability = Applicability({
$id: Now.ID['asset_applicability'],
name: 'Asset Management Users',
roles: [userRole],
});

// 3. Create list configuration (see UxListMenuConfig section)
const assetListConfig = UxListMenuConfig({ /* ... */ });

// 4. Create workspace
export const assetWorkspace = Workspace({
$id: Now.ID['asset_management_workspace'],
title: 'Asset Management',
path: 'asset-management',
tables: ['alm_asset', 'cmdb_ci', 'user'],
listConfig: assetListConfig,
});

// 5. Create ACL -- field MUST match workspace path + .*
Acl({
$id: Now.ID['asset_management_workspace_ACL'],
localOrExisting: 'Existing',
type: 'ux_route',
operation: 'read',
roles: ['x_snc_asset.user'],
table: 'now',
field: 'asset-management.*',
});

UxListMenuConfig API Reference

Defines navigation structure and list views for workspaces -- categories, lists, and role-based visibility.

UxListMenuConfig Properties

NameTypeRequiredDescription
$idNow.ID[string]YesUnique identifier
namestringYesName of the list configuration
descriptionstringNoDescription
activebooleanNoWhether active (default: true)
categoriesUxListCategory[]NoArray of categories

UxListCategory Properties

NameTypeRequiredDescription
$idNow.ID[string]YesUnique identifier
titlestringYesDisplay title in navigation
ordernumberNoSort order (lower = first)
listsUxList[]YesArray of lists

UxList Properties

NameTypeRequiredDescription
$idNow.ID[string]YesUnique identifier
titlestringYesDisplay title
tablestringYesServiceNow table name
columnsstringNoComma-separated column names
conditionstringNoEncoded query filter
ordernumberNoSort order within category
applicabilitiesListApplicability[]NoRole-based visibility

Encoded Query Patterns

condition: 'active=true^EQ'                                           // Active records
condition: '' // All records
condition: 'assigned_toDYNAMIC90d1921e5f510100a9ad2572f2b477fe^EQ' // Assigned to current user
condition: 'priority=1^ORpriority=2' // High priority

UxListMenuConfig Example

const listConfig = UxListMenuConfig({
$id: Now.ID['itsm_workspace_list_config'],
name: 'ITSM Workspace List Configuration',
categories: [
{
$id: Now.ID['incidents_category'],
title: 'Incidents',
order: 10,
lists: [
{
$id: Now.ID['incidents_open'],
title: 'Open',
order: 10,
condition: 'active=true^EQ',
table: 'incident',
columns: 'number,short_description,priority,state',
applicabilities: [{
$id: Now.ID['incidents_open_applicability'],
applicability: userApplicability,
}],
},
{
$id: Now.ID['incidents_all'],
title: 'All',
order: 20,
condition: '',
table: 'incident',
columns: 'number,short_description,priority,state',
applicabilities: [{
$id: Now.ID['incidents_all_applicability'],
applicability: userApplicability,
}],
},
],
},
],
});

Dashboard API Reference

The Dashboard fluent plugin defines the landing page for workspaces. Dashboards are organized into tabs containing widgets.

Dashboard Properties

NameTypeRequiredDescription
$idNow.ID[string]YesUnique identifier
namestringYesDisplay name
tabsDashboardTab[]YesArray of tabs
visibilitiesDashboardVisibility[]YesLinks dashboard to workspaces
permissionsDashboardPermission[]YesAccess control (can be empty)

Widget Properties

NameTypeRequiredDescription
$idNow.ID[string]YesUnique identifier
componentstringYesVisualization type
componentPropsobjectYesComponent configuration
heightnumberYesHeight in grid units
widthnumberYesWidth in grid units
position{x, y}YesGrid position

Grid Layout System

Dashboards use a 48-point grid. Common layouts:

  • Full width: { width: 48, position: { x: 0, y: 0 } }
  • Three columns: widths 14, 17, 17 at x positions 0, 14, 31

Widget Component Types

Visualizations:

ComponentDescriptionData Type
single-scoreSingle metric displaySimple
vertical-barVertical bar chartGroup
horizontal-barHorizontal bar chartGroup
lineLine chartTrend
donutDonut chartGroup
piePie chartGroup
areaArea chartTrend
dialDial gaugeSimple

Supporting widgets: heading, rich-text, image.

Data Type Requirements

  • Simple (single-score, dial, gauge): requires dataSources and metrics only.
  • Group (vertical-bar, donut, pie): requires dataSources, metrics, and groupBy.
  • Trend (line, area, column): requires dataSources, metrics, and trendBy.

Dashboard Example

import { Dashboard } from '@servicenow/sdk/core';

Dashboard({
$id: Now.ID['incident_dashboard'],
name: 'Incident Dashboard',
tabs: [{
$id: Now.ID['overview_tab'],
name: 'Overview',
widgets: [
{
$id: Now.ID['open_incidents_widget'],
component: 'single-score',
componentProps: {
dataSources: [{
label: 'Incident', sourceType: 'table',
tableOrViewName: 'incident', filterQuery: '',
id: 'data_source_1',
}],
headerTitle: 'Open Incidents',
metrics: [{
dataSource: 'data_source_1', id: 'metric_1',
aggregateFunction: 'COUNT', axisId: 'primary',
}],
},
height: 14, width: 14, position: { x: 0, y: 0 },
},
{
$id: Now.ID['incidents_by_priority_widget'],
component: 'vertical-bar',
componentProps: {
dataSources: [{
label: 'Incident', sourceType: 'table',
tableOrViewName: 'incident', filterQuery: '',
id: 'data_source_1',
}],
headerTitle: 'Incidents by Priority',
metrics: [{
dataSource: 'data_source_1', id: 'metric_1',
aggregateFunction: 'COUNT', axisId: 'primary',
}],
groupBy: [{
groupBy: [{ dataSource: 'data_source_1', groupByField: 'priority' }],
maxNumberOfGroups: 10, showOthers: false,
}],
sortBy: 'value',
},
height: 14, width: 17, position: { x: 14, y: 0 },
},
],
}],
visibilities: [{
$id: Now.ID['dashboard_visibility'],
experience: assetWorkspace,
}],
permissions: [],
});

List API Reference

Configure lists (sys_ui_list) and their views.

NameTypeDescription
tableStringRequired. Table name for the list.
viewReferenceRequired. UI view identifier or default_view.
columnsListElement[]Required. Array of column definitions.
parentTableNameParent table for related lists.

List Element

FieldTypeMandatoryDescription
elementstringYesField name (supports dot walking)
positionnumberNoDisplay position (defaults to array order)
import { List } from '@servicenow/sdk/core';

const myList = List({
table: 'cmdb_ci_server',
view: app_task_view,
columns: [
{ element: 'name', position: 0 },
{ element: 'business_unit', position: 1 },
],
});

Troubleshooting

Dashboard Not Appearing

  • Verify visibilities references the correct workspace.
  • Confirm the workspace URL pattern is correct.

Lists Not Appearing

  • Check active is true for both category and list.
  • Verify applicability includes the user's roles.
  • Ensure listConfig is referenced in the workspace.

Workspace Not Accessible

  • Check ACL field matches {workspace.path}.* exactly.
  • Verify users have required roles.