Lambda Cold Start API Gateway: Serverless Optimization

AWS Serverless: Lambda, API Gateway, and Step Functions Deep Dive

Introduction

Serverless computing eliminates infrastructure management, enabling developers to focus purely on code. AWS provides three core serverless services: AWS Lambda for event-driven compute, Amazon API Gateway for building APIs, and AWS Step Functions for orchestrating distributed workflows.

This guide explores serverless architecture patterns, Lambda execution models, API Gateway integration types, and Step Functions state machines. We'll cover cold start optimization, API caching strategies, and error handling patterns for production workloads.


AWS Developer Certification Series

📚 View Complete AWS Developer Certification Guide - Master all 7 parts with our comprehensive learning path.

This is Part IV (Current Article) of our comprehensive 7-part AWS developer guide:

  1. Part I: IAM EC2 & Auto Scaling
  2. Part II: RDS Aurora & DynamoDB
  3. Part III: SQS SNS & Kinesis
  4. Part IV: Lambda API Gateway (Current Article)
  5. Part V: ECS Fargate & IaC
  6. Part VI: Cognito KMS Security
  7. Part VII: CodePipeline & Monitoring

← Part III: SQS SNS & Kinesis | Part V: ECS Fargate & IaC →


AWS Lambda

Lambda Execution Model

Lambda runs code in response to events without provisioning servers, with automatic scaling and pay-per-use pricing.

   AWS Resources   

   AWS Lambda   

   Event Sources   

   invoke   

   trigger   

   poll   

   poll   

   invoke   

   read/write   

   query   

   upload   

  API Gateway  

  S3 Event  

  DynamoDB Stream  

  SQS Queue  

  EventBridge  

  Lambda Function  

  Runtime Environment  

  Lambda Layers  

  Shared Dependencies  

  DynamoDB  

  RDS Proxy  

  S3 Bucket  

Key Specifications:

  • Memory: 128 MB to 10 GB (CPU scales with memory)
  • Timeout: Maximum 15 minutes
  • Deployment package: 50 MB (zipped), 250 MB (unzipped)
  • Concurrency: 1,000 concurrent executions per region (soft limit)
  • Pricing: $0.20 per 1M requests + $0.0000166667 per GB-second

Lambda Function Example

Node.js Lambda with DynamoDB:

const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const {
  DynamoDBDocumentClient,
  GetCommand,
  PutCommand,
} = require('@aws-sdk/lib-dynamodb');

// Initialize outside handler (reused across invocations)
const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

exports.handler = async event => {
  const userId = event.pathParameters.id;

  try {
    // Get item from DynamoDB
    const response = await docClient.send(
      new GetCommand({
        TableName: process.env.TABLE_NAME,
        Key: { userId },
      }),
    );

    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
      },
      body: JSON.stringify(response.Item),
    };
  } catch (error) {
    console.error('Error:', error);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: error.message }),
    };
  }
};

Invoke Lambda via AWS CLI:

# Synchronous invocation
aws lambda invoke \
  --function-name my-function \
  --payload '{"userId": "123"}' \
  response.json

# Asynchronous invocation
aws lambda invoke \
  --function-name my-function \
  --invocation-type Event \
  --payload '{"userId": "123"}' \
  response.json

Lambda Invocation Types

Synchronous (Request-Response):

  • API Gateway, ALB, Application Code
  • Caller waits for response
  • Retries: Client responsibility

Asynchronous (Event-based):

  • S3, SNS, EventBridge, CloudWatch Events
  • Lambda queues internally, returns immediately
  • Retries: 2 automatic retries with exponential backoff
  • Configure DLQ (SQS/SNS) for failed events

Event Source Mapping (Polling):

  • SQS, Kinesis, DynamoDB Streams
  • Lambda polls source and invokes function
  • Batch processing with configurable batch size

Cold Start Optimization

Best Practices:

  1. Minimize package size - Remove unused dependencies
  2. Increase memory - More RAM = faster CPU and network
  3. Keep functions warm - Use Provisioned Concurrency for critical APIs
  4. Initialize outside handler - Reuse connections across invocations
  5. Use ARM (Graviton2) - 20% price reduction, 19% faster
// ❌ Bad - initializes every invocation
exports.handler = async event => {
  const AWS = require('aws-sdk');
  const dynamodb = new AWS.DynamoDB.DocumentClient();
  // ... rest of code
};

// ✅ Good - reuses connection
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();

exports.handler = async event => {
  // Use existing dynamodb client
};

Amazon API Gateway

API Gateway Architecture

API Gateway creates RESTful and WebSocket APIs with built-in authorization, caching, and throttling.

   Backend Integrations   

   API Gateway   

   Clients   

   HTTPS   

   HTTPS   

   WSS   

  Web Browser  

  Mobile App  

  IoT Device  

  REST API  

  /users, /orders  

  WebSocket API  

  Real-time  

  Authorizer  

  Cognito/Lambda  

  Cache  

  0.5-237 GB  

  Lambda  

  HTTP Endpoint  

  AWS Service  

  DynamoDB, S3  

API Types:

  • REST API: Full features, caching, custom domains
  • HTTP API: Lower cost (70% cheaper), lower latency, simpler
  • WebSocket API: Bidirectional real-time communication

API Gateway Integration Types

Lambda Proxy Integration (AWS_PROXY):

  • Request passes through to Lambda as-is
  • Lambda must return specific response format
  • Most common pattern

Lambda Custom Integration (AWS):

  • Transform request/response using VTL (Velocity Template Language)
  • More control over mapping

HTTP Proxy Integration:

  • Forward to HTTP endpoint

AWS Service Integration:

  • Direct integration with DynamoDB, S3, etc. (no Lambda needed)

Testing API Gateway with curl

# GET request
curl https://api.example.com/users/123

# POST with JSON body
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "email": "john@example.com"}'

# With Authorization header
curl https://api.example.com/users \
  -H "Authorization: Bearer eyJhbGc..."

# With API Key
curl https://api.example.com/users \
  -H "x-api-key: abc123xyz"

# Invalidate cache for specific request
curl https://api.example.com/users \
  -H "Cache-Control: max-age=0"

API Gateway Authorizers

Lambda Authorizer Example:

exports.handler = async event => {
  const token = event.authorizationToken; // From Authorization header
  const methodArn = event.methodArn;

  // Validate token (JWT, API key, etc.)
  const isValid = await validateToken(token);

  if (isValid) {
    return generatePolicy('user123', 'Allow', methodArn, {
      userId: 'user123',
      role: 'admin',
    });
  } else {
    throw new Error('Unauthorized');
  }
};

function generatePolicy(principalId, effect, resource, context = {}) {
  return {
    principalId,
    policyDocument: {
      Version: '2012-10-17',
      Statement: [
        {
          Action: 'execute-api:Invoke',
          Effect: effect,
          Resource: resource,
        },
      ],
    },
    context, // Available in Lambda via event.requestContext.authorizer
  };
}

API Gateway Caching

Enable caching per stage:

  • Cache size: 0.5 GB to 237 GB
  • TTL: 0 to 3600 seconds
  • Per-method cache settings override stage settings

Cache key parameters:

  • Query string parameters
  • Request headers
  • Path parameters

Invalidate cache:

  • Manually via console/API
  • Client request with Cache-Control: max-age=0 header (requires IAM permission)

AWS Step Functions

Step Functions State Machine

Step Functions orchestrates distributed workflows with visual state machines and built-in error handling.

   yes   

   no   

  Start  

  Validate Order  

  Lambda Task  

  Valid?  

  Process Payment  

  Lambda Task  

  Update Inventory  

  DynamoDB Task  

  Send Notification  

  SNS Task  

  Handle Error  

  Lambda Task  

  Success  

  Fail  

State Types:

  • Task: Invokes Lambda, ECS, Batch, or AWS service
  • Choice: Conditional branching
  • Parallel: Execute branches concurrently
  • Wait: Delay for duration or until timestamp
  • Map: Iterate over array
  • Succeed/Fail: Terminal states

Step Functions Example

State Machine Definition:

{
  "Comment": "Order processing workflow",
  "StartAt": "ValidateOrder",
  "States": {
    "ValidateOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:validate",
      "Next": "ProcessPayment",
      "Catch": [
        {
          "ErrorEquals": ["ValidationError"],
          "Next": "OrderFailed"
        }
      ],
      "Retry": [
        {
          "ErrorEquals": ["States.TaskFailed"],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 2.0
        }
      ]
    },
    "ProcessPayment": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:payment",
      "Next": "UpdateInventory"
    },
    "UpdateInventory": {
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:updateItem",
      "Parameters": {
        "TableName": "inventory",
        "Key": {
          "product_id": { "S.$": "$.productId" }
        },
        "UpdateExpression": "SET stock = stock - :qty",
        "ExpressionAttributeValues": {
          ":qty": { "N.$": "$.quantity" }
        }
      },
      "Next": "OrderComplete"
    },
    "OrderComplete": {
      "Type": "Succeed"
    },
    "OrderFailed": {
      "Type": "Fail",
      "Error": "OrderValidationFailed"
    }
  }
}

Start Execution with AWS SDK (Node.js):

const { SFNClient, StartExecutionCommand } = require('@aws-sdk/client-sfn');

const client = new SFNClient({});

async function startWorkflow(orderId, productId, quantity) {
  const command = new StartExecutionCommand({
    stateMachineArn:
      'arn:aws:states:us-east-1:123456789012:stateMachine:order-processing',
    input: JSON.stringify({
      orderId,
      productId,
      quantity,
    }),
  });

  const response = await client.send(command);
  console.log('Execution ARN:', response.executionArn);
  return response.executionArn;
}

Production Best Practices

Lambda Best Practices

  1. Memory Allocation: Start with 512 MB, monitor CloudWatch metrics, adjust (more RAM = faster CPU)
  2. Cold Starts: Use Provisioned Concurrency for latency-sensitive APIs (costs more)
  3. Environment Variables: Store config, use AWS Systems Manager Parameter Store for secrets
  4. Timeout: Set appropriate timeout (default 3s, max 15 min)
  5. VPC: Only if accessing private resources (adds cold start overhead)
  6. Layers: Share dependencies across functions (max 5 layers per function)

API Gateway Best Practices

  1. Caching: Enable for GET requests with stable data (reduces Lambda invocations)
  2. Throttling: Set per-stage limits (default 10,000 requests/sec)
  3. Request Validation: Use JSON schema validation to reject malformed requests early
  4. API Keys: For partner/external API access control (use Usage Plans)
  5. Custom Domains: Use Route 53 + ACM for branded APIs

Step Functions Best Practices

  1. Error Handling: Always configure Retry and Catch blocks
  2. Timeouts: Set appropriate timeouts for each state (prevents stuck executions)
  3. Standard vs Express:
    • Standard: Long-running (max 1 year), auditable, exactly-once execution
    • Express: High-volume, short-duration (max 5 min), at-least-once
  4. Cost Optimization: Use Express for high-throughput workloads (60% cheaper)

Monitoring and Troubleshooting

Key Metrics:

Lambda:

  • Invocations - Number of times invoked
  • Errors - Failed invocations
  • Duration - Execution time
  • Throttles - Requests throttled due to concurrency limits
  • ConcurrentExecutions - Number of running instances

API Gateway:

  • Count - Total API requests
  • 4XXError / 5XXError - Client/server errors
  • Latency - Request processing time
  • CacheHitCount / CacheMissCount - Cache performance

Step Functions:

  • ExecutionsFailed - Failed executions
  • ExecutionTime - Workflow duration
  • ExecutionThrottled - Throttled executions

Exam Tips

Key Concepts:

  1. Lambda timeout maximum is 15 minutes (use Step Functions for longer workflows)
  2. Lambda@Edge runs at CloudFront edge locations (max 128 MB memory, 5s timeout)
  3. API Gateway cache sizes: 0.5 GB to 237 GB, TTL 0 to 3600s
  4. Step Functions Express max 5 minutes, Standard max 1 year
  5. Lambda Provisioned Concurrency keeps instances warm (reduces cold starts)

Common Scenarios:

  • "Need to run code for 30 minutes" → Step Functions + Lambda (chain functions)
  • "Reduce API latency" → API Gateway caching + Provisioned Concurrency
  • "Lambda cold starts" → Increase memory, use Provisioned Concurrency
  • "Orchestrate microservices" → Step Functions
  • "Real-time bidirectional communication" → API Gateway WebSocket
  • "Process 10,000 items in parallel" → Step Functions Map state

Frequently Asked Questions

Q: What is AWS Lambda and how does it work?

AWS Lambda is a serverless compute service that runs code in response to events without provisioning servers. You upload code, configure triggers like API calls or S3 uploads, and Lambda automatically scales execution. You pay only for compute time consumed, measured in milliseconds. Maximum execution time is 15 minutes.

Q: How do I reduce Lambda cold start latency?

Reduce cold starts by increasing memory allocation (faster CPU), using Provisioned Concurrency to keep instances warm, minimizing deployment package size, avoiding VPC unless necessary, and choosing interpreted languages like Python or Node.js. Provisioned Concurrency costs more but eliminates cold starts for critical APIs.

Q: What is the difference between API Gateway REST API and HTTP API?

REST API offers advanced features like request validation, caching, usage plans, and API keys with higher cost. HTTP API is simpler, 70% cheaper, faster, and supports OIDC/JWT authorization natively. Use HTTP API for cost-sensitive modern applications, REST API when you need caching or throttling.

Q: When should I use Step Functions instead of Lambda?

Use Step Functions when orchestrating multiple services, requiring workflows longer than 15 minutes, needing visual workflow tracking, or implementing complex error handling with retries. Lambda alone works for simple event processing. Step Functions coordinates Lambda functions, ECS tasks, and AWS services into reliable workflows.

Q: How does Lambda concurrency work?

Lambda concurrency is the number of function instances running simultaneously. AWS provides 1,000 concurrent executions per region by default (can be increased). When exceeded, requests are throttled. Reserved concurrency guarantees capacity for critical functions. Monitor ConcurrentExecutions metric to avoid throttling.

Q: What are API Gateway stages and how are they used?

API Gateway stages represent different deployment environments like dev, test, and production for the same API. Each stage has independent settings for caching, throttling, and logging. Promote APIs through stages using stage variables and canary deployments for gradual traffic shifting.

Q: How do Step Functions handle errors and retries?

Step Functions use Retry and Catch blocks in state definitions. Retry specifies automatic retry attempts with exponential backoff for transient errors. Catch handles specific error types and transitions to fallback states. This provides robust error handling without writing complex retry logic in application code.


Conclusion

AWS serverless services enable building scalable applications without managing infrastructure. Lambda provides event-driven compute with automatic scaling, API Gateway creates secure APIs with built-in features, and Step Functions orchestrates complex workflows with visual state machines.

Choose Lambda for event-driven processing, API Gateway for RESTful and WebSocket APIs, and Step Functions for coordinating distributed services. Understanding execution models, integration patterns, and optimization techniques is essential for both production serverless architectures and the AWS Certified Developer Associate exam.