Skip to content

Add a Custom Node Type

Custom nodes let you extend Workflow Builder with node types that match your specific domain and business logic.

Each node type consists of four files inside apps/frontend/src/app/data/nodes/<node-name>/:

FilePurpose
schema.tsJSON Schema defining the node’s properties
uischema.tsUI Schema controlling how properties render
default-properties-data.tsDefault values for all properties
<node-name>.tsNode definition (label, type, icon) exported to the palette

Create apps/frontend/src/app/data/nodes/my-node/my-node.ts:

import { PaletteItem } from '@workflow-builder/types/common';
import { defaultPropertiesData } from './default-properties-data';
import { MyNodeSchema, schema } from './schema';
import { uischema } from './uischema';
export const myNode: PaletteItem<MyNodeSchema> = {
label: 'My Node',
description: 'Does something useful',
type: 'my-node',
icon: 'Star',
defaultPropertiesData,
schema,
uischema,
};

Create schema.ts to define what properties the node has:

import { NodeSchema } from '@workflow-builder/types/node-schema';
export const schema = {
properties: {
label: { type: 'string' },
description: { type: 'string' },
targetService: {
type: 'string',
options: [
{ label: 'Email', value: 'email' },
{ label: 'Slack', value: 'slack' },
{ label: 'Webhook', value: 'webhook' },
],
},
},
} satisfies NodeSchema;
export type MyNodeSchema = typeof schema;

Create uischema.ts to control layout and field rendering:

export const uischema = {
type: 'VerticalLayout',
elements: [
{ type: 'Control', scope: '#/properties/label' },
{ type: 'Control', scope: '#/properties/description' },
{
type: 'Control',
scope: '#/properties/targetService',
options: { format: 'dropdown' },
},
],
};

Create default-properties-data.ts:

export const defaultPropertiesData = {
label: 'My Node',
description: '',
targetService: 'email',
};

Add the new node to the palette in apps/frontend/src/app/data/palette.ts:

import { myNode } from './nodes/my-node/my-node';
const getPaletteDataFunction = (): PaletteItemOrGroup[] => {
return [
triggerNode,
action,
// ...existing nodes
myNode, // add here
];
};

The new node type now appears in the palette and can be dragged onto the canvas.

Use rules in the UI Schema to show or hide fields based on other field values:

{
type: 'Control',
scope: '#/properties/webhookUrl',
rule: {
effect: 'SHOW',
condition: {
scope: '#/properties/targetService',
schema: { const: 'webhook' },
},
},
}

This renders webhookUrl only when targetService is 'webhook'.

The properties form is rendered by JSONForms. The schema.ts and uischema.ts files follow the JSONForms JSON Schema and UI Schema specifications. Refer to the JSONForms docs for the full list of layouts, controls, rules, and renderers.

See also: Node Library overview