Skip to content
Innovation & Growth

One Next.js Config Line Pushed Memory Use to 4.4GB in Three Minutes

A copy-pasted Edge runtime directive triggered a WASM memory leak and an SSRF gap in a Next.js image route.

K
Kannan SP
· 4 min read
Share on X LinkedIn
One Next.js Config Line Pushed Memory Use to 4.4GB in Three Minutes
Key finding

RSS memory after a 3-minute load test, before fix: 4,404MB (Source: Engineering post, siddarthkay.com, PR #264 (Sept 2026))

A three-minute climb to 4.4GB

An engineering post published on siddarthkay.com in September 2026 traces a recurring container crash on a Next.js-based publishing platform at Logos back to a single line of configuration. Under load testing, the container's memory climbed steadily until the host killed and restarted it, then the climb repeated. Logs pointed to a RuntimeError inside a WASM module loaded by the site's Open Graph (OG) image generator, the route that builds the preview images shown when a page is shared on social media.

One directive, wrong rendering pipeline

The OG route carried an `export const runtime = 'edge'` directive at the top of the file, which the post's author says was likely copied from a Vercel tutorial. On Vercel's own Edge network that line is harmless. Deployed to a standard Node.js container, Next.js still honors it, and because the Edge runtime's built-in image renderer isn't available outside Vercel, the framework falls back to rendering SVGs with @resvg/resvg-wasm, the library behind @vercel/og. That fallback has a known memory leak: every render allocates WASM memory that is not released afterward. On a route generating an image for every page on the site, the leak compounds quickly. Removing the single runtime directive switched the route to a standard Node handler using next/og instead, avoiding the leaky path entirely.

4,404MB
RSS memory after a 3-minute load test, before fix
Source: Engineering post, siddarthkay.com, PR #264 (Sept 2026)
2,571MB RSS, heap flat at 148MB
RSS memory after the same test, after fix
Source: Engineering post, siddarthkay.com, PR #264 (Sept 2026)

Two more caches with no ceiling

While auditing the route, the author found two other unbounded in-memory stores that weren't the primary leak but would have caused problems on a long-running server: a placeholder-image cache that added a base64 string on every image processed during static-site revalidation with no eviction, and a search-index cache that accumulated a new inverted index per query with no limit. Both were capped with FIFO eviction, at 500 entries and 50 entries respectively.

The same route accepted an arbitrary URL

The OG generator also took an image URL as a request parameter and fetched whatever it pointed to before embedding it in the rendered image. Without restriction, that parameter let the route be used as a proxy to reach internal services, a server-side request forgery path. The fix added an allowlist of permitted image hosts and a URL-sanitizing function ahead of the fetch.

One account, not a census, but a common pattern

This is a single engineering team's fix on its own codebase, not a disclosed vulnerability or a survey of how many sites carry the same directive. But the pattern it describes, an Edge runtime export left in an image-generation route on a deployment outside Vercel's own infrastructure, sits on top of the framework WebPulse's scanners see most often. In a September 2026 scan of the Tranco top-10,000 domains, Next.js was detected on 791 of the 2,491 sites where a platform was identified, a 31.8% share. That scale is a reason a routing directive that, in the author's words, 'sounds harmless,' is worth a specific look.

31.8% (791 of 2,491 sites)
Next.js share of detected frameworks, Tranco top 10,000 domains
Source: WebPulse scan of Tranco top-10,000 domains (Sept 2026)

What to ask engineering

Budget holders whose teams run Next.js outside Vercel's managed Edge network have three concrete questions worth putting on the agenda: does any route still carry a runtime: 'edge' export, and what rendering path does it fall back to under load on the current hosting target? Are there in-memory caches, image, search, or session, without an eviction limit that could grow for the life of the server? And does any route that fetches a URL supplied in a request parameter check that URL against an allowlist before making the request?

Share this insight