In December 2022 JRahm, with Jim_Deucker, published an "iRules Style Guide" on F5's DevCentral community: a handful of editor settings and twenty numbered rules. It reads like a house style, and much of it is, but several rules are there because breaking them causes real failures. Grouping the rules by what they protect makes the reasons clearer. The guide and its twelve replies were read in full on 2026-10-03, and every behaviour below was run in a real tclsh 8.4.6, the Tcl version F5 names for iRules (K6091).
Rules that keep an iRule loading
- R11, a space between
}and{.if { $x }{ ... }is not a style problem in Tcl 8.4: the parser stops with "extra characters after close-brace", and the iRule does not load. A keyword glued to its brace fails too, only later: Tcl readsif{as a single word, the name of a command that does not exist. F5's own reference page forreturnhas exactly that slip in its example. - R1, no smart quotes or no-break spaces. Text pasted from a word processor can carry characters that look identical to the real ones. A no-break space glues two words into one command name, and curly quotes do not group words at all. The family is wider than the two the guide names: zero-width spaces, the and the other characters lists as default-ignorable are invisible, and an en dash typed where
--belongs is taken byswitchas the value, so nothing matches and nothing complains. - R2, the size limit. The guide says 64 KB; F5 K9204 gives the exact figure, 65,520 characters, and BIG-IP refuses to save or load a longer iRule ("Max string size exceeded", "max:65520"). K9204 suggests splitting the code into separate iRules on the same virtual server; the guide's advice on reaching the limit is to question the design of the solution rather than to squeeze.
The guide demonstrates R1 by accident. As published on 2026-10-03, its RULE_INIT example has a ZERO WIDTH SPACE (U+200B) right after the closing brace, and its debug example has a line that holds nothing else. Copied verbatim, the first stops Tcl 8.4.6 with "extra characters after close-brace" and the second runs as a command named after an invisible character. The style checker names each such character with its code point, its Unicode name and its column.
Rules that keep request data from steering the rule
- R12, brace every expression. Without braces,
expr,ifandwhilesubstitute their argument twice, so a value from the request can run as code. F5 K15650046 is the security advisory and K57410758 the warning BIG-IP writes when it loads a configuration with an unbraced expression; that warning is informational, does not stop the load, and does not catch every case. The guide's "deep dive" link now leads to a 2014 DevCentral article that disassembles the bytecode: unbraced, Tcl builds the expression as a string at run time and hands it to the expression engine; braced, the compiler handles it ahead of time, and in the article's example even computes the constant answer (the disassembler it uses needs Tcl 8.5 or later). F5's How To Write Fast Rules puts the speed cost at "a factor of 20 or so". - R15, end options with
--.switchreads any word starting with a dash as an option. A Host header such as-globcould change how your switch matches, and an unknown one stops the iRule with "bad option". K15650046 shows the exact log line. The guide asks for--onswitchandtable;class matchtakes it too. - R13 and R14, spaces and braces around variables in expressions.
if { ${host} eq "a" }leaves no doubt where the variable name ends, and it reads the same in every editor.
Rules that keep behaviour predictable
- R9, store state as 0 or 1. In an
if, 0 is false and every other number is true, -1 included. Tcl also accepts true, yes and on, and false, no and off, in either case and abbreviated as long as the short form is not ambiguous:nandofare false,tis true, andois an error. Andstring is true -1returns 0 whileiftreats -1 as true. One spelling, 0 or 1, removes all of that; the zero-or-one finder has the details. - R10,
&&and||rather thanandandor. F5's word operators work, but F5 does not document where they sit in the precedence table; the Tcl operators, with parentheses, leave nothing to guess. - R16, a priority on every event. F5's
prioritypage sets the default at 500 and the range from 0 to 1000, with lower numbers running first. Writing it down means the order of several iRules on one virtual server is a decision, not an accident. - R17, a timeout or lifetime on every table entry. F5's
tablereference gives an entry a default timeout of 180 seconds and an indefinite lifetime when none is set; writing them down makes the entry's life a decision. The guide also asks whether the table is needed at all, and suggests thestatic::namespace as the alternative for configuration-like values. - R18 and R19, careful with
static::. Static variables are shared by every connection; prefix their names so two iRules cannot collide, and do not use them for debug switches, which the guide names as a leading cause of log storms.
Rules that keep it readable
- Editor settings: 4-space indents with no tabs, a 100-column goal (120 at most), , line feeds, no trailing white space, and a final line feed.
- R3, functional blocks; R4, the opening brace at the end of the line and
} else {on one line; R5, the 4-space indent carried into nested values such asswitcharms; R7, one command per line; R8, no single-lineif, even for a debug log. - R6, comments on their own line, written
# comment, never at the end of a line and never betweenswitchpatterns, where Tcl reads them as patterns. - R20, no commented-out code in the version that ships.
What the comment thread adds
The replies under the guide are worth reading with it. Three points stand out, and the first two are now checks of their own in the style checker (D1 and D2).
eq for text, == for numbers. Kai Wilke pointed out that the guide's rule 10 example compares text with ==. == and != compare as numbers whenever both sides look like numbers, so all of these are true in Tcl 8.4.6:
% expr {10 == 012}
1
% expr {1 == "0x0000001"}
1
% expr {1 == 1.0}
1
% expr {"1.0" eq "1"}
0
012 is octal, so it equals 10, and eq compares the characters, so "1.0" and "1" differ. Jim Deucker agreed to add a point about eq and ne; as read on 2026-10-03 the example still uses ==. F5's How To Write Fast Rules makes the same point in its own words: compare numbers to numbers and strings to strings, and mind the implicit conversions, == against eq among them.
A switch arm needs no return or break. Juergen Mang noted that he often sees return used to stop a switch arm. An arm never runs into the next one (a body written as - deliberately shares the next pattern's body), so nothing is needed. return leaves the whole event, not just the switch, as F5's return page says. break has nothing to break: switch is not a loop, so inside a loop break leaves the loop, and with no loop around it Tcl 8.4.6 reports "invoked "break" outside of a loop" (checked in a proc body; F5 does not document what TMM does with it in an event). Jim Deucker replied that this was outside the style guide's scope but a candidate for a diagnostic in the VS Code extension.
A corrected example. Kai also spotted that the final example's foreach { f } { ${e} } would loop over the literal text rather than the list in e. JRahm corrected it to foreach { f } ${e}, and the published guide carries the fix.
The editor settings, and what has moved
The guide gives the settings for VS Code, EditorConfig, Vim and Sublime. Two things have changed since it was written:
- The VS Code extension link is dead. The "F5 Networks iRules" extension the guide recommends (
bitwisecook.irule) returned 404 on the Visual Studio Marketplace on 2026-10-03. Its author's current extension is "Tcl/Tk, iRules, EDA-Tools, LSP/" (bitwisecook.tcl-lsp), announced on DevCentral in March 2026 with iRule diagnostics, formatting and taint tracking of user input. "The F5 Extension" (F5DevCentral.vscode-f5) is still listed. - One EditorConfig value is not in the specification. The guide's EditorConfig block sets
charset = ascii, but the EditorConfig specification (version 0.17.2) defines only latin1, utf-8, utf-8-bom, utf-16be and utf-16le, and tells editors to ignore values they do not support. An ASCII file is already valid , soutf-8is the nearest valid setting; keeping the file ASCII is then a job for a checker.
An EditorConfig section with the guide's settings and only specified values:
# iRules files: the DevCentral style guide's editor settings
[*.irule]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
A rule that follows the guide
when HTTP_REQUEST priority 500 {
# Send API traffic to its own pool.
set path [string tolower [HTTP::path]]
switch -glob -- ${path} {
"/api/*" {
pool api_pool
}
default {
pool web_pool
}
}
}
Try it
The iRules style checker reads a pasted iRule against these rules, the two points from the comment thread and a real Tcl 8.4 parse, and names the rule behind each finding. Its "Pasted from a word processor" and "An invisible character" presets show R1 at work. The if / switch / class builder writes decisions in this style from the start, and the expression lab shows == and eq side by side.
This series, in order
This article opens the series The Tcl inside iRules. The style guide's twenty rules, grouped by what they protect, are the map; the parts teach the language underneath them in order: how values compare and how numbers are read, how strings are built and taken apart, how a rule chooses among many values, the loops that block a single-threaded TMM, reusable procedures, the static namespace, measuring cost, and the Node.js process an iRule can call.
- iRules comparisons: == versus eq, precedence, and the quiet fallback to text. == compares numbers when it can and text when it cannot, while eq always compares text.
- Numbers in iRules: octal, hexadecimal, and why 08 is not a number. A leading zero means octal: why 010 is eight and 08 is not a number at all.
- Building strings in iRules: quotes, braces, append, concat and lists. Quotes substitute, braces do not, brackets run a command: the three rules behind almost every surprise.
- Tcl string commands in iRules: indexes, map, match, compare and trim. Indexes, map, match, compare and trim, and the one rule people get wrong in each.
- findstr, substr and getfield: what F5 documents, and what it leaves open. F5's three commands for cutting a piece out of a value, what the documentation says and what it leaves open.
- scan in iRules: taking values apart without regular expressions. Taking values apart without a regular expression, and why its result counts conversions rather than matches.
- iRules: choosing between if, switch, class match, and static arrays. Chained if, switch, a data group with class match, or a static array: choosing how to match one value against many.
- Loops and lists in iRules, and why they block. foreach, for and while, and why a large loop per request stalls the connection it runs in.
- iRules procedures: reusable code with proc and call. Code defined once with proc and called from anywhere, including from iRules attached to nothing.
- iRules, CMP, and the static:: namespace. How one global variable demotes a virtual server to a single core, and static:: as the cure.
- iRules performance: cycles, timing, and the runtime calculator. The bytecode inside TMM, what the timing command measures, and why average cycles is the number to trust.
- iRules LX, explained: what runs where when Tcl calls Node.js. A Node.js process beside the microkernel, called from Tcl, and what runs where.
Sources
The rules and the replies are quoted from the guide's page; the security, warning, size, priority and table details come from the F5 pages it relies on; every Tcl behaviour was reproduced in Tcl 8.4.6. All read on 2026-10-03.
- F5 DevCentral: iRules Style Guide (JRahm with Jim_Deucker, 2022-12-22), with its comment thread
- F5 K9204: iRules are limited to 65,520 characters
- F5 K15650046: Tcl code injection security exposure
- F5 K57410758: use curly braces to avoid double substitution
- F5 K6091: The version of Tcl used to develop iRules
- F5 iRules reference: How To Write Fast Rules
- F5 iRules reference: return
- F5 iRules reference: priority
- F5 iRules reference: table
- F5 DevCentral: Advanced iRules, an abstract view of iRules with the Tcl bytecode disassembler (2014)
- F5 DevCentral: iRule Developer Tools (2026)
- Visual Studio Marketplace: Tcl/Tk, iRules, EDA-Tools, Expect LSP/MCP
- Visual Studio Marketplace: The F5 Extension
- EditorConfig Specification 0.17.2
- Tcl 8.4 manual: if
- Tcl 8.4 manual: switch
- Tcl 8.4 manual: break
- Unicode Character Database 18.0.0: DerivedCoreProperties.txt