Performance and Limits
The DVE engine caches compiled templates and guards each render with a set of limits, so large pages stay fast and a runaway template fails loudly instead of hanging the server. Every limit is configured under views on the Router options.
Caching
A template is compiled once, then the parsed result is reused on every later render:
// First render compiles and caches
await ctx.render('template', data)
// Later renders reuse the cache
await ctx.render('template', newData)The cache covers compilation only, not data or backend logic. Editing the file clears its entry through hot reload, so the next render compiles the new source.
Iteration Limit
Each {{#each}} block is capped at 100_000 iterations by default, which keeps one unbounded loop from starving the event loop. The engine checks the array length before emitting any item, so an oversized loop fails fast. Tune it with views.maxIterations:
const router = new Router({
views: {
directory: './views',
maxIterations: 200_000
}
})When a loop exceeds the cap, the engine throws and the server responds with 400 Bad Request. For very large datasets, reach for streaming rendering. For CPU-heavy rendering, offload to a worker pool.
Render Budget Limits
Two more caps guard the whole render rather than a single loop. maxRenderIterations sums every {{#each}} body execution across the page, including nested loops, and defaults to 1_000_000. maxOutputSize caps the total characters one render may produce and defaults to 5_000_000:
const router = new Router({
views: {
directory: './views',
maxRenderIterations: 500_000,
maxOutputSize: 2_000_000
}
})Crossing either cap responds with 400 Bad Request, the same status as the per-loop limit. Keep maxRenderIterations at or above maxIterations, otherwise a single large loop trips the total cap first.
Template Size Limit
maxTemplateSize caps the characters of a single template source, checked at compile time, and defaults to 1_000_000. The same cap applies to every included or layout file the engine resolves. An oversized source throws before parsing begins, which responds with 400 Bad Request:
const router = new Router({
views: {
directory: './views',
maxTemplateSize: 500_000
}
})Include Depth Limit
Template includes and layout chains share a cap of 64 levels of nesting, so a circular or runaway chain throws instead of looping forever. Crossing the cap responds with 400 Bad Request. Keeping partials and layouts shallow stays well within this limit, which is covered alongside the include and layout syntax.