Chunking an Array with ColdFusion Redux
Revisiting chunking ColdFusion arrays in 2025 cfmlJuly 17, 2025 / Robert Zehnder
Still talking about chunking arrays? Yep.
It’s been four years since my original post, and while it’s not something I deal with daily, chunking comes in handy — especially when working with large payloads that need to be split for APIs or batch processing.
Over the years, I’ve experimented with several versions of this logic. Not all code is created equal — some are more readable, others more performant. What works great on small arrays can crawl on larger ones. So, I decided to revisit this, benchmark a few versions, and share the results.
For testing, I generated an array of 100,000 elements using randomized data:
source = [];
for (i = 1; i <= 100000; i++) {
source[i] = randRange(1, 9999, "SHA1PRNG");
}
Readable? Yes. Fast? Not really. This version averaged 1300ms on BoxLang and Adobe 2025 — making it the slowest.
function chunkArrayV1(input, chunkSize) {
var output[1] = [];
var currentChunk = 1;
input.each((item, index) => {
output[currentChunk].append(item);
if (index % chunkSize == 0 && index < input.len()) {
output[++currentChunk] = [];
}
});
return output;
}
Surprisingly performant — especially on newer engines like BoxLang and Lucee 6. Less so on Lucee 5.
function chunkArrayV2(input, chunkSize) {
var out = [];
for (var i = 1; i <= ceiling(input.len() / chunkSize); i++) {
out.append(
i == ceiling(input.len() / chunkSize)
? input.slice(1 + (i - 1) * chunkSize, input.len() - ((i - 1) * chunkSize))
: input.slice(1 + (i - 1) * chunkSize, chunkSize)
);
}
return out;
}
A more readable take on V2, and my previous go-to. Performance was solid across engines.
function chunkArrayV3(input, chunkSize) {
var out = [];
var ceil = ceiling(input.len() / chunkSize);
for (var i = 1; i <= ceil; i++) {
var t = [];
var offset = (i - 1) * chunkSize;
if (i == ceil) {
var c = input.len() - offset < chunkSize ? input.len() - offset : chunkSize;
for (var x = 1; x <= c; x++) {
t.push(input[offset + x]);
}
} else {
for (var x = 1; x <= chunkSize; x++) {
t.push(input[offset + x]);
}
}
out.push(t);
}
return out;
}
An optimized and elegant revision of V3. Slightly better performance across most engines.
function chunkArrayV4(input, chunkSize) {
var out = [];
var ln = input.len();
for (var i = 1; i <= ln; i += chunkSize) {
var t = [];
var end = min(i + chunkSize - 1, ln);
for (var j = i; j <= end; j++) {
t.append(input[j]);
}
out.append(t);
}
return out;
}
A refined version of V2 — and the top performer across every engine (except Lucee 5).
function chunkArrayV5(input, chunkSize) {
var out = [];
var len = input.len();
var chunkCount = ceiling(len / chunkSize);
for (var i = 1; i <= chunkCount; i++) {
var offset = (i - 1) * chunkSize;
var count = min(chunkSize, len - offset);
out.append(input.slice(offset + 1, count));
}
return out;
}
BoxLang
Source: 100,000 elements
chunkArrayV1() - 1455ms
chunkArrayV2() - 39ms
chunkArrayV3() - 687ms
chunkArrayV4() - 663ms
chunkArrayV5() - 27ms
Adobe ColdFusion 2025
Source: 100,000 elements
chunkArrayV1() - 62044ms 🤯
chunkArrayV2() - 23ms
chunkArrayV3() - 93ms
chunkArrayV4() - 41ms
chunkArrayV5() - 3ms 🔥
Lucee 5
Source: 100,000 elements
chunkArrayV1() - 93ms
chunkArrayV2() - 1001ms
chunkArrayV3() - 110ms
chunkArrayV4() - 51ms
chunkArrayV5() - 1001ms
Lucee 6
Source: 100,000 elements
chunkArrayV1() - 124ms
chunkArrayV2() - 5ms
chunkArrayV3() - 81ms
chunkArrayV4() - 60ms
chunkArrayV5() - 4ms