or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdcli.mdfunction-nodes.mdhttp-services.mdindex.mdnode-development.mdruntime.mdutilities.md

function-nodes.mddocs/

0

# Function Nodes

1

2

JavaScript execution environment and APIs available within Node-RED Function nodes. Function nodes provide a secure sandbox for running custom JavaScript code with access to Node-RED's messaging system and context storage.

3

4

## Capabilities

5

6

### Function Node Context

7

8

Global objects and APIs available in the Function node execution environment.

9

10

```javascript { .api }

11

/**

12

* Available in Function node context

13

*/

14

interface FunctionNodeGlobals {

15

/** Current message being processed */

16

msg: NodeMessage;

17

/** Node instance with control methods */

18

node: NodeInstance;

19

/** Node-scoped persistent storage */

20

context: ContextStore;

21

/** Flow-scoped persistent storage */

22

flow: ContextStore;

23

/** Global-scoped persistent storage */

24

global: ContextStore;

25

/** Environment variables access */

26

env: EnvironmentVariables;

27

/** Node-RED utilities subset */

28

RED: NodeREDUtilities;

29

}

30

31

/**

32

* Message object structure

33

*/

34

interface NodeMessage {

35

/** Unique message identifier */

36

_msgid: string;

37

/** Message topic (optional) */

38

topic?: string;

39

/** Message payload (any type) */

40

payload: any;

41

/** Additional message properties */

42

[key: string]: any;

43

}

44

```

45

46

**Basic Function Node Example:**

47

48

```javascript

49

// Simple message transformation

50

msg.payload = msg.payload.toString().toUpperCase();

51

msg.timestamp = Date.now();

52

return msg;

53

54

// Multiple outputs

55

if (msg.payload > 10) {

56

return [msg, null]; // Send to first output only

57

} else {

58

return [null, msg]; // Send to second output only

59

}

60

61

// Multiple messages to same output

62

return [

63

[

64

{ payload: "First message" },

65

{ payload: "Second message" }

66

],

67

null

68

];

69

```

70

71

### Node Instance Methods

72

73

Methods available on the `node` object for controlling node behavior and output.

74

75

```javascript { .api }

76

/**

77

* Node instance methods

78

*/

79

interface NodeInstance {

80

send(msg: NodeMessage | NodeMessage[], clone?: boolean): void;

81

error(err: string | Error, msg?: NodeMessage): void;

82

warn(warning: string | object): void;

83

log(info: string | object): void;

84

status(status: NodeStatus | string | boolean | number): void;

85

done(err?: Error): void;

86

}

87

88

/**

89

* Send message(s) to connected nodes

90

* @param msg - Message or array of messages to send

91

* @param clone - Whether to clone messages before sending (default: true)

92

*/

93

node.send(msg: NodeMessage | NodeMessage[], clone?: boolean): void;

94

95

/**

96

* Log error and trigger catch nodes

97

* @param err - Error message or Error object

98

* @param msg - Optional message that caused the error

99

*/

100

node.error(err: string | Error, msg?: NodeMessage): void;

101

102

/**

103

* Log warning message

104

* @param warning - Warning message or object

105

*/

106

node.warn(warning: string | object): void;

107

108

/**

109

* Log informational message

110

* @param info - Info message or object

111

*/

112

node.log(info: string | object): void;

113

114

/**

115

* Set node status indicator

116

* @param status - Status object, string, boolean, or number

117

*/

118

node.status(status: NodeStatus | string | boolean | number): void;

119

```

120

121

**Usage Examples:**

122

123

```javascript

124

// Send processed message

125

msg.payload = processData(msg.payload);

126

node.send(msg);

127

128

// Send without cloning (more efficient but potentially unsafe)

129

node.send(msg, false);

130

131

// Error handling

132

try {

133

msg.payload = JSON.parse(msg.payload);

134

node.send(msg);

135

} catch (err) {

136

node.error("Invalid JSON in payload", msg);

137

}

138

139

// Status updates

140

node.status({ fill: "blue", shape: "ring", text: "processing..." });

141

// Clear status

142

node.status({});

143

144

// Logging

145

node.log(`Processing message with topic: ${msg.topic}`);

146

node.warn("Deprecated feature used");

147

```

148

149

### Context Storage

150

151

Persistent storage system available at node, flow, and global scopes.

152

153

```javascript { .api }

154

/**

155

* Context storage interface

156

*/

157

interface ContextStore {

158

get(key: string, callback?: (err: Error, value: any) => void): any;

159

get(keys: string[], callback?: (err: Error, values: any[]) => void): any[];

160

set(key: string, value: any, callback?: (err: Error) => void): void;

161

set(keys: string[], values: any[], callback?: (err: Error) => void): void;

162

keys(callback?: (err: Error, keys: string[]) => void): string[];

163

}

164

165

/**

166

* Get value from context (synchronous)

167

* @param key - Context key or array of keys

168

* @returns Value or array of values

169

*/

170

context.get(key: string | string[]): any;

171

172

/**

173

* Get value from context (asynchronous)

174

* @param key - Context key or array of keys

175

* @param callback - Callback function

176

*/

177

context.get(key: string | string[], callback: (err: Error, value: any) => void): void;

178

179

/**

180

* Set value in context

181

* @param key - Context key or array of keys

182

* @param value - Value to store or array of values

183

* @param callback - Optional callback function

184

*/

185

context.set(key: string | string[], value: any, callback?: (err: Error) => void): void;

186

187

/**

188

* Get all context keys

189

* @param callback - Optional callback function

190

* @returns Array of keys (if synchronous)

191

*/

192

context.keys(callback?: (err: Error, keys: string[]) => void): string[];

193

```

194

195

**Context Storage Examples:**

196

197

```javascript

198

// Node-scoped storage (persists across messages for this node)

199

const counter = context.get("counter") || 0;

200

context.set("counter", counter + 1);

201

202

// Flow-scoped storage (shared across all nodes in this flow)

203

const flowData = flow.get("sharedData") || {};

204

flowData.lastUpdate = Date.now();

205

flow.set("sharedData", flowData);

206

207

// Global storage (shared across all flows)

208

const globalConfig = global.get("config") || {};

209

210

// Store selection with specific store

211

const value = context.get("key", "file"); // Get from file store

212

context.set("key", "value", "memory"); // Set in memory store

213

214

// Asynchronous operations

215

context.get("asyncKey", (err, value) => {

216

if (!err) {

217

node.log(`Retrieved: ${value}`);

218

}

219

});

220

221

// Multiple keys

222

const values = context.get(["key1", "key2", "key3"]);

223

context.set(["key1", "key2"], ["value1", "value2"]);

224

225

// Get all keys

226

const allKeys = context.keys();

227

```

228

229

### Environment Variables

230

231

Access to environment variables and Node-RED predefined variables.

232

233

```javascript { .api }

234

/**

235

* Environment variables interface

236

*/

237

interface EnvironmentVariables {

238

get(name: string): string | undefined;

239

}

240

241

/**

242

* Get environment variable

243

* @param name - Environment variable name

244

* @returns Environment variable value or undefined

245

*/

246

env.get(name: string): string | undefined;

247

```

248

249

**Predefined Environment Variables:**

250

251

- `NR_NODE_ID` - Current node ID

252

- `NR_NODE_NAME` - Current node name

253

- `NR_NODE_PATH` - Current node path

254

- `NR_GROUP_ID` - Parent group ID (if in group)

255

- `NR_GROUP_NAME` - Parent group name (if in group)

256

- `NR_FLOW_ID` - Current flow ID

257

- `NR_FLOW_NAME` - Current flow name

258

- `NR_SUBFLOW_ID` - Subflow instance ID (if in subflow)

259

- `NR_SUBFLOW_NAME` - Subflow name (if in subflow)

260

- `NR_SUBFLOW_PATH` - Subflow path (if in subflow)

261

262

**Usage Examples:**

263

264

```javascript

265

// System environment variables

266

const dbHost = env.get("DATABASE_HOST") || "localhost";

267

const apiKey = env.get("API_KEY");

268

269

// Node-RED predefined variables

270

const nodeId = env.get("NR_NODE_ID");

271

const nodeName = env.get("NR_NODE_NAME") || "Unnamed";

272

const flowName = env.get("NR_FLOW_NAME");

273

274

// Use in logging

275

node.log(`Node ${nodeName} (${nodeId}) in flow ${flowName} processing message`);

276

277

// Conditional logic based on environment

278

if (env.get("NODE_ENV") === "development") {

279

node.log("Debug info:", msg);

280

}

281

```

282

283

### Node-RED Utilities

284

285

Subset of Node-RED utilities available in Function nodes.

286

287

```javascript { .api }

288

/**

289

* Node-RED utilities available in Function nodes

290

*/

291

interface NodeREDUtilities {

292

util: {

293

generateId(): string;

294

cloneMessage(msg: NodeMessage): NodeMessage;

295

setMessageProperty(msg: NodeMessage, prop: string, value: any): boolean;

296

getMessageProperty(msg: NodeMessage, prop: string): any;

297

};

298

}

299

300

/**

301

* Generate unique identifier

302

* @returns Generated ID string

303

*/

304

RED.util.generateId(): string;

305

306

/**

307

* Clone message object safely

308

* @param msg - Message to clone

309

* @returns Cloned message

310

*/

311

RED.util.cloneMessage(msg: NodeMessage): NodeMessage;

312

313

/**

314

* Set property on message using dot notation

315

* @param msg - Target message object

316

* @param prop - Property path (e.g., "payload.data.value")

317

* @param value - Value to set

318

* @returns true if successful

319

*/

320

RED.util.setMessageProperty(msg: NodeMessage, prop: string, value: any): boolean;

321

322

/**

323

* Get property from message using dot notation

324

* @param msg - Source message object

325

* @param prop - Property path (e.g., "payload.data.value")

326

* @returns Property value

327

*/

328

RED.util.getMessageProperty(msg: NodeMessage, prop: string): any;

329

```

330

331

**Usage Examples:**

332

333

```javascript

334

// Generate IDs for tracking

335

const requestId = RED.util.generateId();

336

msg.requestId = requestId;

337

338

// Safe message cloning

339

const backup = RED.util.cloneMessage(msg);

340

341

// Dynamic property access

342

const sensorValue = RED.util.getMessageProperty(msg, "payload.sensors.temperature");

343

RED.util.setMessageProperty(msg, "payload.processed.timestamp", Date.now());

344

345

// Complex property paths

346

const path = "payload.data.items.0.value";

347

const value = RED.util.getMessageProperty(msg, path);

348

if (value !== undefined) {

349

RED.util.setMessageProperty(msg, "payload.firstItemValue", value);

350

}

351

```

352

353

## Advanced Patterns

354

355

### Asynchronous Operations

356

357

```javascript

358

// Using callbacks with context

359

context.get("config", (err, config) => {

360

if (err) {

361

node.error("Failed to get config", msg);

362

return;

363

}

364

365

msg.payload = processWithConfig(msg.payload, config);

366

node.send(msg);

367

});

368

369

// Using setTimeout for delays

370

setTimeout(() => {

371

msg.payload = "Delayed message";

372

node.send(msg);

373

}, 5000);

374

```

375

376

### Multiple Output Handling

377

378

```javascript

379

// Route messages based on conditions

380

const route1 = [];

381

const route2 = [];

382

383

msg.payload.forEach(item => {

384

if (item.type === "urgent") {

385

route1.push({ payload: item });

386

} else {

387

route2.push({ payload: item });

388

}

389

});

390

391

// Send arrays of messages to different outputs

392

node.send([route1, route2]);

393

```

394

395

### Error Handling Patterns

396

397

```javascript

398

try {

399

// Risky operation

400

const result = JSON.parse(msg.payload);

401

msg.payload = result;

402

node.send(msg);

403

} catch (err) {

404

// Send error to catch node

405

node.error(err.message, msg);

406

// Or handle gracefully

407

node.warn("Invalid JSON, using default");

408

msg.payload = {};

409

node.send(msg);

410

}

411

```

412

413

## Types

414

415

```javascript { .api }

416

interface NodeStatus {

417

fill?: 'red' | 'green' | 'yellow' | 'blue' | 'grey';

418

shape?: 'ring' | 'dot';

419

text?: string;

420

}

421

422

interface NodeMessage {

423

_msgid: string;

424

topic?: string;

425

payload: any;

426

[key: string]: any;

427

}

428

```