1. Shrink the bundle first
Tree-shake, import individual functions instead of whole libraries, and prefer platform APIs over utility packages. The measured 9.8x gzipped difference between two validation libraries for one schema shows how much design choice matters Valibot. A practitioner account of trimming a serverless package from 40 MB to under 5 MB reports cold starts dropping by over 400 ms Medium, Ahmedrao. Edge bundle limits force the discipline: one guide cites 1 MB compressed on a free plan and 10 MB on a paid plan for a Workers-style runtime, and 1 MB for another edge platform ResumeLens.
2. Move heavy work out of module scope
Anything at top level runs on every cold start even when that request does not need it. Lazy-load the PDF generator, the email client, the big parser, inside the branch that uses it.
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/report") {
const { renderPdf } = await import("./pdf.js");
return renderPdf(request);
}
return new Response("ok");
},
};
Guidance for a Deno-based edge runtime is the same: avoid top-level await for slow operations and keep bundles small, with functions under 5 MB and minimal imports typically cold-starting under 200 ms RapidDev.
3. Cache connections and computed config in the isolate
Isolates persist between requests until evicted, so a lazily initialized client pays off across a warm window, but never assume it survives Cloudflare. Use a memoized getter, and treat any cached state as disposable.
4. Warm critical routes with scheduled pings
A low-frequency request per region keeps a route hot during predictable traffic, at the cost of billed invocations. Deno-based functions can use a scheduled database job to ping routes RapidDev, and scheduled invocations are a standard mitigation in container-based serverless PayPro Global. Keep the ping route tiny so the warm request itself is cheap.
5. Choose the runtime that matches the job
If you need a filesystem, native modules, or long execution, a Node.js runtime at a region near your data beats a cold-start-optimized edge runtime that cannot run your code. Edge runtimes support web APIs only, with no filesystem, no native modules, and tightly capped execution time OneUptime. Code that reaches for Node crypto, buffers, or dynamic evaluation fails there outright, and a runtime switch is the honest fix dev.to.
6. Deploy in a way that limits recold
Batch releases, pre-warm the new version from a synthetic client before shifting traffic, and keep a small health route to hit. Every deploy creates first invocations PayPro Global, so fewer, larger releases beat many small ones.
7. Co-locate compute with data, or cache the result
If the handler cannot avoid a distant datastore, cache the response at the edge and treat the cold path as the slow path. Infrastructure context on how edge and origin servers interact, and why traffic routes to the nearest node, is worth reading before you redesign Stack Overflow, Imperva.
Decision rule: if your p95 cold start is under roughly 100 ms and warm latency dominates, stop optimizing startup and fix the downstream. If cold adds more than 200 ms over warm, work through bundle size, top-level work, and warming in that order, because those are the levers you control.