Skip Navigation

Help & Reference

Substitution Variables

Every ${…} variable you can use when producing messages: arguments, date and time formats, and what happens when one is wrong.

This page lists every ${…} variable KafkIO understands, with its arguments, what it gives and what happens when one is written wrongly. Variables work in the Produce Message(s) dialog while '${variable}' substitution is ticked: in the key, the message, and header keys and values. How to use them while producing (the option, the counter across a batch, templates) is in Producing Messages.

All variables

Arguments in italics are optional. The example results are real ones, from 26 October 2026 at 12:07.

VariableGivesExample result
${counter}1, 2, 3... one more each time it's used (Counter) 1
${random.int:min:max}A random whole number (Random numbers) ${random.int:60:300} → 187
${random.double:min:max}A random decimal number ${random.double:-5:5} → -2.6552469347229133
${random.string:min:max}Random letters and digits (Random strings and UUIDs) ${random.string:6:6} → WZ8EsC
${random.uuid}A random UUID efe1ca4c-f714-4b32-b270-76c9adaa37e9
${current.date:format}Today's date (Dates and times) 2026-10-26
${current.datetime:format}The date and time now 2026-10-26T12:07:16.444184200
${epoch.seconds}Seconds since 1 January 1970 UTC 1793016436
${epoch.millis}Milliseconds since 1 January 1970 UTC 1793016436444

Syntax

A variable is ${, its name, any arguments each after a colon, and }: ${random.uuid}, ${random.int:1000}, ${random.int:60:300}, ${current.date:dd/MM/yyyy}. A variable can sit anywhere in the text, alone or inside other text: ORD-${current.date:yyyyMMdd}-${counter} gives ORD-20261026-1.

  • Exact names. Names are case-sensitive and can't contain spaces: ${Counter} and ${ counter } are not variables. Anything KafkIO doesn't recognise, such as ${user.name}, is sent exactly as typed, without an error.
  • Arguments only where listed. ${counter}, ${random.uuid} and the epoch variables take none: with one (${counter:5}) they aren't recognised and stay as typed. The random variables take at most two; with three or more, random.int, random.double and random.string ignore them all and behave as if they had none.
  • No variables inside variables. ${random.int:${counter}:9} is an error.
  • A literal ${. Double the dollar sign: $${counter} is sent as ${counter}. To send a whole message full of ${…} text unchanged, untick '${variable}' substitution instead.

Variables are replaced in the text you typed, before the serializer turns it into bytes, so the result must still be valid for the serializer. In JSON (or Avro and Protobuf written as JSON), leave a variable unquoted where a number belongs and quote it where a string belongs: "amount": ${random.int:5:500}, "id": "${random.uuid}".

Every message is built afresh, so each one gets new random values and the current time as it's built. The key is filled in first, then the message, then the headers (each header's key, then its value).

Counter

${counter} starts at 1 every time you click the send button (or Test in the examples window), and goes up by one each time it's used, wherever it's used. A batch of ten messages with one ${counter} in the message gets 1 to 10; with a counter in both the key and the message, the first message gets 1 and 2, the next 3 and 4. Producing Messages shows how to keep them matching.

There's no starting value or step: ${counter} is always 1, 2, 3... for each send. For numbers that carry on from earlier batches, use ${epoch.millis} (always increasing, though not by one) or put a fixed prefix in front: batch2-${counter}.

Random numbers

VariableGives
${random.int}A whole number from 0 to 2,147,483,646
${random.int:min}A whole number from min to 2,147,483,646
${random.int:min:max}A whole number from min up to, but not including, max; exactly min when the two are equal
${random.double}, ${random.double:min}A decimal number from 1 (or min) up to the largest number Java can hold, so nearly always something like 1.5667141473952902E308. Give a range instead.
${random.double:min:max}A decimal number from min up to, but not including, max; exactly min when the two are equal
  • The maximum is never reached. ${random.int:1:7} gives 1 to 6, like a dice roll; ${random.int:1:2} is always 1. Add one to the maximum you want: customer-${random.int:1:21} spreads messages over customer-1 to customer-20. (The examples window's own notes say "<= 300"; the code stops one short.)
  • Negative numbers work: ${random.int:-10:11} gives -10 to 10. random.int arguments must be whole numbers between -2,147,483,648 and 2,147,483,647; random.double accepts decimals (${random.double:0.5:1.5}).
  • Decimals come with every digit. random.double prints as many decimal places as the number has (37.48120934571266), and numbers of 10 million or more in E notation (4.513726254437281E7). For a price with two decimals, build it from whole numbers: ${random.int:1:100}.${random.int:0:10}${random.int:0:10} gives 1.00 to 99.99.

Random strings and UUIDs

VariableGives
${random.string}1 to 63 random characters
${random.string:min}min to 63 characters (min can be at most 64, which gives exactly 64)
${random.string:min:max}min up to, but not including, max characters; exactly min when the two are equal, so ${random.string:8:8} is always 8 characters. No upper limit: ${random.string:1000:1000} works.
${random.uuid}A random (version 4) UUID, 36 characters with dashes

Random strings use only the letters A-Z, a-z and the digits 0-9, so they're safe inside JSON strings, CSV and header values. ${random.string:0:0} gives an empty string.

Dates and times

VariableGives
${current.date}Today's date as yyyy-MM-dd: 2026-10-26
${current.date:format}Today's date in your format, which can't include a time: ${current.date:EEEE d MMMM yyyy} gives Monday 26 October 2026
${current.datetime}The date and time with nine decimal places of seconds: 2026-10-26T12:07:16.444184200
${current.datetime:format}The date and time in your format: ${current.datetime:yyyy-MM-dd'T'HH:mm:ss.SSS} gives 2026-10-26T12:07:16.444
${epoch.seconds}Whole seconds since 1 January 1970 UTC
${epoch.millis}Milliseconds since 1 January 1970 UTC, the form Kafka uses for message timestamps

current.date and current.datetime use your computer's local time and carry no time zone, so no format can show one (it's an error). For a time that means the same everywhere, send ${epoch.millis} or ${epoch.seconds}. Month and day names, and the AM/PM marker, follow KafkIO's language and your computer's region: with English in Ireland, h:mm a gives 12:07 p.m.

Date and time format patterns

Formats are Java date-time patterns: letters stand for parts of the date, and the number of letters sets the style. The common ones, as they print on Monday 26 October 2026 at 12:07:16.444 (14:07 for the hours):

PatternMeaningGives
yyyy, yyYear2026, 26
M, MM, MMM, MMMMMonth 10, 10, Oct, October
d, ddDay of the month (dd pads to two digits) 26, 26 (on the 5th: 5, 05)
EEE, EEEEDay of the weekMon, Monday
DDay of the year299
wWeek of the year (numbering depends on your region)44
Q, QQQQuarter4, Q4
HHHour, 00-2314
hh, hHour, 1-12 (use with a)02, 2
aAM/PM markerp.m. or PM, by region
mmMinutes07
ssSeconds16
SSS, SSSSSSFraction of a second: milliseconds, microseconds 444, 444184
'text'Literal text'T' → T, 'week' w → week 44
''A single quote''yy → '26

Spaces and punctuation such as - / : , . and ( ) print as they are. Every unquoted letter is a pattern letter, so put words in single quotes, as in yyyy-MM-dd'T'HH:mm:ss. The full list is in Java's DateTimeFormatter documentation.

Warning: case matters. MM is the month and mm the minutes; HH is 24-hour and hh 12-hour. YYYY is a week-based year, which is a year off for a few days around New Year (on 29 December 2025 it already gives 2026): use yyyy.

Trying variables out

Before sending anything, test a variable or a date format in Variables Substitution Examples: click Examples next to '${variable}' substitution in the Produce dialog (The examples window). Type your own text in the top box and click 1 Test; the counter starts again at 1 on every test.

The Variables Substitution Examples window with eight lines typed into the Examples box and their results below. isoTime ${current.datetime:yyyy-MM-dd'T'HH:mm:ss.SSS} gives 2026-10-26T12:07:16.444. longDate ${current.date:EEEE d MMMM yyyy} gives Monday 26 October 2026. clock ${current.datetime:h:mm a} gives 12:07 p.m. weekDay ${current.date:'week' w, 'day' D} gives week 44, day 299. orderId ORD-${current.date:yyyyMMdd}-${counter} gives ORD-20261026-1. price ${random.int:1:100}.${random.int:10:100} gives 28.83. label ${random.string:6:6} gives WZ8EsC. literal $${counter} gives ${counter}. The Test button is under the results. 1
Your own lines in the top box, and what they give below.
  1. Test: substitutes the top box again, with fresh random values and the time now.

When a variable is wrong

A mistake in a recognised variable's arguments stops the send: an Exception Details window opens with Error sending message(s) and the reason, and no message is sent (the same reason appears in the examples window after Test). The reason is Java's, and doesn't say which variable failed:

You wroteWhat happens
${Counter}, ${ counter }, ${user.name}, ${counter:5}Not a variable: sent as typed
${random.int:1.5}, ${random.int:abc} For input string: "1.5" (random.int needs whole numbers)
${random.int:5:1}, ${random.string:100} For example min (100) must be less than or equal to max (64)
${random.int:${counter}:9}For input string: "${counter"
${current.date:HH:mm}Unsupported field: HourOfDay: a date has no time; use current.datetime
${current.datetime:XXX}, ${current.datetime:z} Unsupported field: OffsetSeconds, Unable to extract ZoneId from temporal: no time zones (Dates and times)
${current.date:today}Unknown pattern letter: t: quote words ('today')

Examples

  • A unique key per message: ${random.uuid}, or order-${counter} when the key is the only place using the counter.
  • Messages spread over 20 keys, and so across partitions: customer-${random.int:1:21}.
  • An ISO 8601 local timestamp: "${current.datetime:yyyy-MM-dd'T'HH:mm:ss.SSS}".
  • An event time as a number: ${epoch.millis}.
  • A price: ${random.int:1:100}.${random.int:0:10}${random.int:0:10}.
  • A fixed-length code: ${random.string:6:6}.
  • A dated order number: ORD-${current.date:yyyyMMdd}-${counter}.
  • A trace header: header key trace-id, value ${random.uuid}.