An iRule is , and Tcl inside the Traffic Management Microkernel (TMM) is fast because it does little: no threads, no sockets of its own, no libraries beyond what F5 compiled in. iRules LX (Language eXtensions) is the answer F5 gave in 2016 to the requests that did not fit that box: parse this JSON properly, look this user up in a database, sign this with a library nobody will port to Tcl 8.4. It does not make Tcl faster or richer. It puts a Node.js process next to TMM and gives the iRule three commands to talk to it. Everything that is good and everything that is awkward about iRules LX follows from that one sentence.
What it is, and what it is not
iRules LX "takes advantage of the capabilities of Node.js to enhance the data plane programmability of a BIG-IP system", in F5's words, and it comes in two modes. The first, remote procedure call (RPC), arrived with BIG-IP 12.0 and became usable without an early-access licence in 12.1: a Tcl iRule, still the thing attached to the virtual server, calls a named JavaScript function and uses what comes back. The second, streaming, arrived in 13.0: the Node.js side receives the flow itself, through the TCP, SSL, HTTP compression and web acceleration profiles, and can act on the data as it passes. Nearly everything written about iRules LX, and nearly everything deployed, is the first mode, and that is what this article is about until the streaming section near the end.
What iRules LX is not: a replacement for the iRule. The LX rule is a normal Tcl iRule with ILX commands in it; it is parsed by the same Tcl 8.4 interpreter, attached to the same virtual server, and subject to the same event model. Node.js is a helper the rule calls, not a place where the rule lives. It is also not the same thing as iControl LX or iApps LX, which are Node.js on the control plane, for management and automation; iRules LX is Node.js in the data path, on the same box, per request.
The objects
Four objects, and the path each one lives on, because the paths matter when something breaks.
A workspace is a directory under /var/ilx/workspaces/<partition>/<workspace_name>/, with extensions/ and rules/ beneath it. F5 describes it as "a portable development package environment with NPM-like directory structure", and portable is the operative word: a workspace can be exported from one BIG-IP and imported on another, which is how code written in a lab reaches production. The path is Local Traffic, iRules, LX Workspaces; the menu only appears once ILX is provisioned under System, Resource Provisioning.
An extension is one Node.js program inside the workspace, at extensions/<extension_name>/: an index.js, a package.json, and the node_modules it needs. One workspace can hold several extensions.
An LX rule is the Tcl iRule, under rules/, that calls the extension. It is an ordinary iRule in every respect except that it uses the ILX commands below.
A plugin is what the system runs. It is built from a workspace ("Reload from Workspace" in the GUI, modify ilx plugin <plugin_name> from-workspace <workspace_name> in tmsh) and published by copying the result to /var/sdm/plugin_store/plugins. The plugin, not the workspace, is what the ILX commands name; editing the workspace changes nothing until the plugin is reloaded from it.
The call path, command by command
Three Tcl commands, all introduced in BIG-IP 12.0 and all documented in the iRules API reference.
ILX::init <plugin> <extension> creates "a handle for future use by ILX::call and ILX::notify. This handle is a reference to a running ILX plugin extension." It may be used in any event except RULE_INIT, which is the first thing that surprises people: the handle cannot be cached once at load time in a static:: variable, because RULE_INIT is excluded. The reference page adds a sentence worth reading twice: "Instances of the plugin extension will be held in draining mode as long as there are open references to the ILX handle in any event." A handle kept alive keeps a draining extension instance alive with it, so a plugin reload waits on rules that are still holding handles.
ILX::call <handle> [-timeout n] <method> [arg]+ is the synchronous call. n is in milliseconds and the default is 3000, three seconds, during which the connection's event handler is waiting. The return value "is the argument passed to response.reply() call on the extension side": a JavaScript array or dictionary comes back as a Tcl list, anything else as a Tcl string. The API reference states one hard limit: "There is a 65K limit to the amount of data that can be sent via the ILX::call command." A request body larger than that does not go to Node.js in one call.
ILX::notify <handle> <method> [arg]+ is the asynchronous one. It "does not wait for the method to complete before returning"; the return value is TCL_OK if "the message was successfully queued", and a failure otherwise. Nothing comes back from the method. It is the right command for logging, counting and side effects whose result the rule does not need.
On the Node.js side, the extension loads F5's module and registers methods:
var f5 = require('f5-nodejs');
var ilx = new f5.ILXServer();
ilx.addMethod('lookup', function (req, res) {
var args = req.params(); // the arguments ILX::call passed, in order
res.reply(['group-a', 'group-b']); // an array comes back to Tcl as a list
});
ilx.listen();
addMethod(name, function(req, res)) names the method the Tcl side calls, req.params() returns the arguments, res.reply(value) sends the answer, and ilx.listen() starts serving. The same module carries the classes the reference lists for the rest of the surface: ILXPlugin, ILXPluginOptions and ILXLbOptions for streaming, ILXStream, ILXFlow, ILXTransaction and ILXHttpRequest for the data they carry, ILXDatagroup and ILXTable for reaching the BIG-IP's own data groups and the session table from JavaScript, ILXBufferUtil and ILXLogger.
Processes, and how many of them
An extension runs as one or more Node.js processes, and the choice is a property of the extension. In dedicated mode, the default, there is "one Node.js process per TMM per extension"; F5's guidance recommends it for "CPU intensive operations" and high-traffic applications, because each TMM has its own worker and none waits on another. In single mode there is "one Node.js process per extension" shared by every TMM, which suits "light weight processes" with low traffic and costs less memory.
The number adds up quickly: extensions multiplied by TMMs, on every blade. F5's own best-practice article from the launch year puts the ceiling plainly: "no more than 50 active Node processes on your BIG-IP at one time (per appliance or per blade)." tmsh show ilx plugin shows each process with its CPU, memory, connection counts and process id, and is the first command to run when a plugin misbehaves. F5's bug tracker also records cases of Node.js processes "consuming excessive memory" (ID 941481), which is a reminder that these are ordinary processes competing with TMM for the box.
npm, on a box with no internet
Extensions use npm packages like any Node.js program, with two constraints F5 states. Modules are installed locally, inside extensions/<extension_name>/, never globally: "when you export the workspace to another BIG-IP, a module installed globally won't be included." And "you can not install native modules", the ones written in C++ that need compiling on the target. A production BIG-IP normally has no route to the npm registry, so the recommended practice is to build the workspace "in a lab that has internet access" and export it, node_modules included, to the other systems.
The Node.js version, which is the part that ages
This is where iRules LX shows its date. A workspace has a node-version property, and the two values F5's current documentation names are 0.12 and 6.9.1. Node.js 6 (Boron) was first released on 26 April 2016 and received its last release on 3 April 2019; the Node.js project's current lines, as the same page reads today, are 24 and 22, with 20 in maintenance. An iRules LX extension written in 2026 runs on a JavaScript engine whose last release is seven years old, and any package that declares a newer engine in its package.json will refuse to install on it.
BIG-IP 21.1 removes the older of the two: "iRules LX no longer supports Node.js v0.12", and "If you use iRules LX workspaces based on Node.js v0.12, you must update them to Node.js v6 to maintain functionality." The release notes say affected workspaces are flagged during the upgrade and log messages identify them. The documented procedure is short:
tmsh list ilx workspace <workspace_name> all-properties
tmsh modify ilx workspace <workspace_name> node-version 6.9.1
tmsh modify ilx plugin <plugin_name> from-workspace <workspace_name>
or, in the GUI, the Node.js Version drop-down on the workspace set to 6.9.1 followed by Reload from Workspace on the plugin. F5 adds the caution that matters: "If the Node modules in your current workspace is not compatible with Node.js 6, you may encounter errors", and the remedy is a new workspace or reinstalled modules.
The version property has a history of its own. Bug ID 746078, "Upgrades break existing iRulesLX workspaces that use node version 6", affected BIG-IP 13.1.0 through 14.1.2.4: a system upgrade reverted a workspace's node version to the default 0.12, and the plugin then failed on reload with "Error: No such module: ILXServerWrap". The workaround was to edit the node_version file under /var/ilx/workspaces/<partition>/<workspace name> by hand before reloading; the fix, in 14.1.2.5 and 15.0.0, "prevented the node version from getting reverted to default during an upgrade." Anyone operating iRules LX across upgrades should read that bug once, because its shape, a per-workspace setting silently reset, is the shape of most iRules LX upgrade surprises.
Streaming mode, briefly
From 13.0 an extension can be a stream handler rather than a method server. The Node.js side creates an ILXPlugin, configures it with ILXPluginOptions and ILXLbOptions, and listens for the initialized and connect events; each flow then emits data, error and requestComplete. The flow is delivered through the TCP, SSL, HTTP compression and web acceleration profiles, which is F5's way of saying the data reaches Node.js after the proxy has done its work. It is the right tool for a protocol TMM does not speak and the wrong one for anything a profile or a Tcl rule can already do, because every byte of the flow now crosses into a process outside TMM and back.
When to use it, and when not to
The honest case for iRules LX is a specific one: a per-request decision that needs a library or a data source Tcl cannot reach, with an answer small enough for 65K and fast enough for a three-second ceiling, on a box with the memory for the processes. User lookups in an external database, F5's own launch example, fit it. Token handling that needs a real JSON parser fits it. Anything that could be a data group, a sideband connection, an APM policy or a plain Tcl rule should stay there, because each ILX::call adds a process boundary, a serialisation and a wait to the request path.
Before a design depends on it, the questions a reviewer should ask:
- Which Node.js version does the workspace declare, and does every package in
node_modulesinstall and run on 6.9.1 today, with no native module among them? - How many Node.js processes will this add (extensions times TMMs times blades, in dedicated mode), and what does
show ilx pluginreport once it is loaded? - What happens when
ILX::calltimes out? Is the call wrapped incatch, and does the rule have a safe default when it is? - Is anything sent to
ILX::callable to approach 65K, and what does the rule do then? - Could
ILX::notifycarry it instead, because the rule does not need the answer? - Where is the handle taken, since
ILX::initcannot run inRULE_INIT, and does any event hold it longer than it needs to? - Who owns the workspace export, where is it kept, and has the import been rehearsed on the target version?
- Is the upgrade path tested with the plugin loaded, including a reload from workspace after the upgrade?
- Does the box have a route to anything the extension connects to, and what is the extension's own timeout to that service, relative to the three seconds Tcl will wait?
- Would the same logic be simpler on the control plane, in iControl LX or outside the BIG-IP altogether, with the data path consuming a result rather than computing it?
A checker for the first question, the one that bites most often, is queued on this site's roadmap; until it exists, npm ls inside the extension directory and the engines field of each package's package.json are the manual version.
Sources
- F5 BIG-IP iRulesLX API reference index (read 2026-10-04): the RPC mode from TMOS 12.1.0, streaming from 13.0.0, the f5-nodejs classes
- F5 iRulesLX API Reference (read 2026-10-04): ILXServer, addMethod, req.params, res.reply, listen; ILXPlugin events; the 65K limit on ILX::call
- F5 iRules API: ILX::init (read 2026-10-04): the handle, ANY_EVENT except RULE_INIT, draining mode, introduced in 12.0 and available without an EA licence from 12.1
- F5 iRules API: ILX::call (read 2026-10-04): the -timeout option and its 3000 ms default, the return value mapping
- F5 iRules API: ILX::notify (read 2026-10-04): does not wait, TCL_OK when queued
- BIG-IP iRulesLX User Guide, version 12.1.0 (PDF), Internet Archive copy of 11 June 2026 (read 2026-10-03 at cdn.f5.com; that address answered 404 on 2026-10-05, confirmed with a second client, while the iRulesLX home on clouddocs still links it; the archived bytes carry the same digest from 2019 to June 2026): workspace and plugin store paths, dedicated and single modes, ILX provisioning
- BIG-IP 21.0.0 release notes: Upgrade Node.js version of iRule LX Workspace (updated 09/02/2026, read 2026-10-04): 0.12 no longer supported from 21.1, the 6.9.1 procedure in GUI and tmsh, the module compatibility caution
- New Features in BIG-IP Version 21.1.0 (updated 09/02/2026, read 2026-10-04): removal of Node.js v0.12 support, workspaces flagged during upgrade
- F5 Bug ID 746078: Upgrades break existing iRulesLX workspaces that use node version 6 (read 2026-10-04): 13.1.0 to 14.1.2.4, the ILXServerWrap error, the workaround, fixed in 14.1.2.5 and 15.0.0
- F5 Bug ID 941481: iRules LX nodejs processes consuming excessive memory (title read 2026-10-03)
- DevCentral: Introducing iRules LX, Danny Luedke, 13 May 2016 (read 2026-10-04): the launch description, workspaces as a portable NPM-like package, the MySQL lookup example
- DevCentral: Getting Started with iRules LX, Part 4: NPM and Best Practices, Eric Flores, 9 June 2016 (read 2026-10-04): local installs, no native modules, the lab-and-export practice, dedicated versus single, the 50-process ceiling, show ilx plugin
- Node.js previous releases (read 2026-10-04): v6 Boron first released 26 April 2016, last updated 3 April 2019; the current LTS lines