Ch. 15 · AWS

AWS Lambda Cold Starts and Warm Reuse

Reduce cold-start latency with smaller packages, provisioned concurrency and initialization outside the handler.

~2 min readintermediateupdated Oct 5, 2026

When Lambda scales a function or retires an idle instance, it creates a new execution environment: download code, initialize the runtime, run your init code, then handle the first request. That startup is the cold start, and its cost depends on package size, runtime, and how much work you do at module scope.

Before you start

You should understand Lambda basics such as handlers and invocation. This article focuses on latency and reuse; it assumes a Node.js-style handler.

Step-by-step walkthrough

Step 1: Shrink the deployment package

Cold-start time grows with the size of the code and dependencies that must be loaded. Tree-shake or bundle only what the handler uses, avoid pulling in large SDKs wholesale, and prefer the lightweight runtime clients. A smaller package means faster download and initialization.

Step 2: Initialize once, reuse across invocations

Code outside the handler runs once per execution environment and is reused by later invocations. Create clients, load configuration and warm caches at module scope, and guard lazy initialization so concurrent warm invocations do not duplicate the work.

Step 3: Reserve capacity for latency-critical paths

Provisioned concurrency keeps environments initialized and ready, removing cold starts for the traffic it covers. It costs money, so apply it to interactive endpoints and leave background or batched functions on on-demand scaling.

Worked scenario

The client is created once and reused by every warm invocation.

let client;
export const handler = async (event) => {
  client ??= await createClient();
  return client.handle(event);
};
JavaScript

Walk through the example

The first invocation creates client and pays the connection cost; subsequent invocations on the same environment reuse it because the module state persists. The ??= guard keeps the creation idempotent if two invocations race. This moves work out of the per-request path, which is the same reason heavy imports are avoided.

Common mistake

Creating a new database or HTTP client inside the handler on every invocation, which adds latency and connection churn. Another is assuming a warm environment is guaranteed: it can be recycled at any time, so never store request-specific data in module state.

Verify the behavior

Check the CloudWatch Init Duration metric for cold-start time and the Duration for handler time. Invoke repeatedly and confirm later invocations skip initialization. Measure latency before and after enabling provisioned concurrency on the same function.

Interview exercise

A function reconnects to the database on every call. Why is that slow, and what is the fix?

Answer and reasoning

Each call pays the connection and authentication cost, and it opens more connections than needed. Move the client to module scope so warm invocations reuse it, guarded by a lazy initializer. If connections still churn across many environments, put a connection proxy in front, because concurrency times a per-environment pool can exceed the database’s connection limit.

Continue learning

Compare invocation behavior in Lambda execution and Lambda retries. Read the AWS Lambda cold start documentation and try the AWS interview questions.

More in AWS

read ✓AWS · hard

AWS DynamoDB Query vs Scan

Read by key with Query, avoid full-table Scans, and add indexes to serve the access patterns you actually have.

~2 min readread →
esc