3 min read

Tame Lambda cold starts in a serverless backend

Cut Lambda cold starts across a large serverless backend. Shrink the artifact, pick a fast runtime, keep init lean, and use provisioned concurrency last.

SaaS production readinessAWSLambdaServerlessPerformance

When you run a handful of Lambdas, cold starts feel like a curiosity. When you run dozens, they become a latency budget you have to manage. I learned this operating a backend of 100+ functions for the New York Lottery platform. Here are the levers that worked, in the order I reach for them.

What a cold start actually is

Lambda runs your function in an execution environment. When no warm environment is free, Lambda creates a new one, loads your code, and runs your initialization before it handles the request. That setup is the cold start. Reuse of a warm environment skips it. The AWS Lambda best practices guide is the reference worth keeping open.

Shrink the artifact

Cold start time tracks how much code the runtime has to load and initialize. Smaller packages start faster. You cut size three ways.

  1. Remove dependencies you do not use, and tree shake the ones you keep.
  2. Split shared code into layers so each function stays small.
  3. Give each function one job. Least privilege functions are also smaller functions.

Pick a fast runtime

Runtime choice changes your baseline. Compiled runtimes like Go start fast and use little memory. On a latency sensitive path, a Go handler on the provided.al2023 custom runtime routinely beats a heavier interpreted one. AWS documents building Lambda functions in Go.

func handler(ctx context.Context, req events.APIGatewayV2HTTPRequest) (events.APIGatewayV2HTTPResponse, error) {
	return events.APIGatewayV2HTTPResponse{StatusCode: 200, Body: "ok"}, nil
}

Keep initialization lean

The work outside your handler runs on every cold start. Keep it small. Create clients once and reuse them across invocations. Load configuration lazily instead of pulling everything at startup. Read secrets once and cache them. The less you do before the first request, the faster that request returns.

Use provisioned concurrency last

Provisioned concurrency keeps environments initialized and ready, so it removes cold starts on the functions you apply it to. It also costs money around the clock, warm or not. Use it only on the few endpoints where p99 latency truly matters, and lean on the cheaper techniques everywhere else. The provisioned concurrency docs explain how to size it.

The takeaway

You solve most cold start pain before you ever pay for provisioned concurrency. Smaller artifacts, a fast runtime, and lean initialization get you most of the way. To see how this fits a full serverless stack, read how I host the frontend on S3 and CloudFront.

Frequently asked questions

What causes a Lambda cold start?

Lambda creates a new execution environment when no warm one is available. It loads your code and runs your initialization before the first request, and that added time is the cold start.

Does my language choice matter?

Yes. Compiled runtimes such as Go start faster and use less memory than heavier interpreted stacks. For latency sensitive endpoints, that baseline difference shows up at p99.

Will provisioned concurrency remove cold starts?

On the functions you apply it to, yes. It keeps environments initialized. The tradeoff is a steady cost, so reserve it for the endpoints that need it.

How do I measure cold starts?

Look at the Init Duration field in your CloudWatch logs and function metrics. It appears only on invocations that ran a cold start, so you can track how often they happen and how long they take.

Does more memory reduce cold starts?

More memory gives a function more CPU, which can speed up initialization for compute heavy startups. It is not a fix on its own. Start with a smaller artifact and lean init, then tune memory.

Comments

    Leave a comment