AWS Lambda Invocation, Cold Starts, and Container Lifecycle

User Icon By Azam Akram,   Calendar Icon July 6, 2025
aws lambda cold start

AWS Lambda is a powerful serverless compute service that automatically runs user code, without the need to provision or manage servers. It automatically handles scaling and provisioning of the execution environment. This makes it a very good choice for applications that respond to events, such as HTTP requests, scheduled tasks and etc.

Behind the scenes, Lambda takes a unique approach to resource efficiency. Instead of keeping every function constantly running (which would be costly and wasteful), Lambda dynamically sets up the execution environment only when your code needs to run. Understanding how this environment is created, reused, and eventually cleaned is key to optimizing both performance and cost.

In this blog, I’ll cover:

  • What triggers a Lambda function
  • What is cold start
  • How long a Lambda stays “warm”
  • What are lambda containers
  • The lifecycle of a Lambda execution environment
  • The role of init(), main(), and your handler function in Go

Note: I will provide code examples using the Go programming language.

If you are looking to learn how to set up AWS Lambda functions with API Gateway and dynamodb, this blog will guide you through the complete process with working example.

What triggers a Lambda function

AWS Lambda is event-driven, meaning it executes your code in response to specific events rather than running continuously. These events can originate from a wide range of AWS services, making Lambda a flexible and reactive service, such as,

  • Scheduled Events: Using Amazon EventBridge, you can configure Lambda to run on a fixed schedule (e.g., every 5 minutes or at midnight daily), similar to a cron job.
  • HTTP Requests: By integrating Lambda with Amazon API Gateway or an Application Load Balancer, your function can be invoked by RESTful or HTTP requests, enabling you to build serverless APIs.
  • S3 Events: When a file is uploaded, modified, or deleted in an S3 bucket, Lambda can respond to that event, which is useful for tasks like image processing or data ingestion.
  • Messaging Services: Lambda can consume messages from Amazon SQS queues, SNS topics, or even Kinesis and DynamoDB Streams, allowing you to process events asynchronously and at scale.

When any of these events occur, Lambda automatically locates an existing execution environment (if available) or creates a new one (if not). It then loads your code and invokes the handler function with the event data. This on-demand execution model is what enables Lambda to scale instantly, respond in real time, and remain cost-efficient; since you only pay when your code runs.

What are Lambda Containers

In AWS Lambda, a container refers to the isolated execution environment that runs your function code. You can think of it as a lightweight, managed sandbox that includes everything your function needs to execute, without you having to set up or maintain any infrastructure.

Each Lambda container is provisioned automatically by AWS and includes the following components:

  • Runtime Environment: This is the language-specific runtime you can select when creating the function, for example, Python 3.12, Node.js 20, Go 1.x, or Java 17.
  • Your Function Code: The actual code you wrote, what gets executed when the function is invoked.
  • Configuration Settings: These include environment variables, memory allocation, timeout duration, VPC settings (if applicable), and other function-level options.
  • Storage: Each container comes with a temporary file system.

What is Cold Start

A cold start occurs when AWS Lambda needs to create a new execution environment (container) to run your function. This happens in situations such as:

  • The function is invoked for the first time
  • AWS scales out to handle increased concurrent invocations
  • An existing container has been idle for a period (typically 10–15 minutes)

Unlike a warm start, a cold start involves additional setup steps before your code can be executed.

What Happens During a Cold Start?

When a cold start is triggered, AWS performs the following phases behind the scenes:

1. Provisioning

  • AWS allocates required resources and creates a new isolated container for your function.
  • It sets up networking, applies IAM permissions, and mounts temporary storage.

2. Initialization

  • The selected runtime environment (e.g., Go, Python, Node.js) is loaded into memory.
  • Your function code is extracted from the deployment package.
  • AWS executes any global setup code. For example, in Go, this includes the init() function, followed by main() calling lambda.Start(...) to register your handler

Once initialization is complete, AWS invokes your function’s handler with the incoming event.

Cold Start Duration

The latency introduced by a cold start can vary based on several factors:

  • Runtime language: Go and Java generally have longer cold starts than Python or Node.js
  • Package size: Larger deployment packages or container images take longer to load
  • VPC configuration: Attaching a function to a VPC introduces additional setup time
  • Initialization logic: Complex setup code (e.g., database connections, config loading) can increase duration

Cold starts usually last between 100 milliseconds and 1+ second, depending on the above conditions.

Minimizing Cold Starts

To reduce cold start impact:

  • Invoke your function periodically (e.g., using CloudWatch Events) to keep the container alive
  • Use provisioned concurrency for consistent, low-latency performance
  • Keep initialization logic lightweight and avoid unnecessary setup outside the handler

Understanding and optimizing cold starts is crucial for latency-sensitive applications, especially APIs or real-time systems.

What is Warm Start

A warm start occurs when AWS Lambda reuses an already-initialized container to handle a new function invocation. Since all the heavier task, such as provisioning resources and loading your code, was done previously, warm starts are significantly faster and more efficient than cold starts.

Warm starts deliver consistently low latency, often in just a few milliseconds. This leads to faster response times and better user experiences.

What Happens During a Warm Start?

  • Provisioning and initialization are skipped: AWS doesn’t need to create a new container, attach networking, or load the runtime again.
  • Execution jumps directly to the handler function: In languages like Go, this means init() and main() are not executed again. Only your registered handler runs, with the new event payload.
  • Temporary storage (/tmp) is preserved: Any files written to the /tmp directory during a previous invocation remain available, which can be useful for caching or reusing intermediate data.
  • Persistent resources may still be available: If your code opened long-lived connections (e.g., to a database or external API) and stored them in a global variable, they may still be active and reusable, reducing connection overhead.

How long a Lambda stays warm

Lambda containers stay alive for around 10–15 minutes of inactivity.

  • Every time a new request comes in, the idle timer resets.
  • If the function remains idle beyond that, AWS may terminate the container.

If your Lambda keeps getting triggered (e.g., once every 5 minutes), it may stay warm indefinitely.

Example: Cold Start and Invocation Flow in Go

To better understand how AWS Lambda initializes and invokes a function, let’s walk through a simple Go example. This helps illustrate which parts of your code run during a cold start, and which run during each function invocation.

package main

import (
    "context"
    "log"
    "github.com/aws/aws-lambda-go/lambda"
)

func init() {
    log.Println("init() - runs once during cold start")
}

func main() {
    log.Println("main() - starts Lambda handler")
    lambda.Start(Handler)
}

func Handler(ctx context.Context, _ interface{}) error {
    log.Println("Handler - runs on each invocation")
    // Your business logic here
    return nil
}
  • init(): Runs once per container (Cold Start Only), this function is called automatically by the Go runtime before main() and runs once per container lifecycle. It’s the good place for one-time setup logic, like loading configurations or initializing shared resources. Note: It will not run again if the container is reused (warm start).
  • main(): Registers the Handler and Starts the Runtime. This is the entry point of the program, just like in any Go application. It’s executed once per cold start, right after init(). The lambda.Start(Handler) call tells the Lambda runtime which function should handle incoming events.
  • Handler(): Runs on Every Invocation. This is the function that gets invoked every time the Lambda function is triggered, whether it’s a cold start or a warm start. It receives the context.Context and the event payload (in this case, ignored using _ interface{}). This is where your actual business logic goes—reading input, processing data, returning a response, etc.

Optimizing for Cold Starts

Cold starts can cause a delay when AWS Lambda needs to set up a new environment to run your function. While they’re rare (usually under 1% of invocations), they can still impact user experience, especially for low-traffic or latency-sensitive applications.

Here are practical ways to reduce the impact of cold starts:

1. Use Lightweight Dependencies

The more code and libraries your function needs to load, the longer it takes to start.

  • Keep your deployment package small, remove unused dependencies.
  • Use standard libraries or minimal third-party packages whenever possible.
  • Avoid bundling large SDKs or frameworks unless absolutely necessary.

2. Minimize Global Setup (e.g., in init())

In Go and many other languages, any code outside the handler, like in init() which runs only during cold starts.

  • Avoid doing heavy operations like:
    • Loading large config files
    • Initializing database clients with slow connections
    • Running long computations

Instead, move such logic to run only when needed, or defer it to the handler.

3. Lazy-Load Inside the Handler

Lazy loading means you initialize resources only when they are first needed, and reuse them afterward.

Example in Go:

var dbClient *DB

func Handler(ctx context.Context, event interface{}) error {
    if dbClient == nil {
        dbClient = connectToDB() // Only connects when first used
    }
    // Rest of your logic
    return nil
}

Conclusion

Understanding how AWS Lambda works behind the scenes — from cold starts and warm starts to the role of containers and function lifecycle — is key to building efficient and responsive serverless applications.

While cold starts are rare and often fast, they can still impact performance in certain scenarios. By keeping your code lightweight, minimizing global setup, and using lazy loading, you can significantly reduce cold start latency. And for critical use cases, Provisioned Concurrency ensures your functions are always ready to respond instantly.

With the right design choices, AWS Lambda can deliver the scalability, cost-efficiency, and low-maintenance benefits that make serverless computing so powerful.