AWS Lambda is the easiest compute service to start with and one of the trickiest to optimize at scale. Cold starts affect user-facing APIs. Memory misconfiguration wastes money. Connection pools exhaust database limits. These best practices address every production Lambda challenge with concrete solutions. This guide focuses on AWS Lambda best practices, with the production trade-offs senior engineers need to make sound decisions.
⚡ TL;DR: Initialize connections outside handler — reused across invocations. Set memory based on Power Tuning results, not guesses. Use Provisioned Concurrency for user-facing functions. X-Ray for distributed tracing. Lambda Layers for shared dependencies. Always set timeout < downstream service timeout.
Handler structure — reuse expensive resources — AWS Lambda best practices
// Good: initialize OUTSIDE handler (reused across warm invocations)
const { Pool } = require('pg');
const pool = new Pool({ connectionString: process.env.DB_URL, max: 1 });
// max:1 — Lambda has 1 concurrent execution per instance
const { SSMClient, GetParameterCommand } = require('@aws-sdk/client-ssm');
const ssm = new SSMClient({ region: 'us-east-1' }); // Reused!
// Lazy-load secrets — cached in module scope
let cachedApiKey;
const getApiKey = async () => {
if (!cachedApiKey) {
const cmd = new GetParameterCommand({Name:'/api/key',WithDecryption:true});
cachedApiKey = (await ssm.send(cmd)).Parameter.Value;
}
return cachedApiKey;
};
exports.handler = async (event) => {
const apiKey = await getApiKey(); // Cached after first call
const db = await pool.connect();
try {
const result = await db.query('SELECT ...');
return { statusCode: 200, body: JSON.stringify(result.rows) };
} finally {
db.release(); // Return to pool!
}
};Memory and timeout configuration
# Lambda Power Tuning (open source) finds optimal memory:
# State machine tests your function at: 128,256,512,1024,2048,3008MB
# Returns cost vs performance graph
# Common finding: 512MB runs 3x faster than 128MB at same cost
# (CPU scales with memory allocation)
# Timeout rules:
# Set LOWER than calling service timeout
# API Gateway timeout: 29s → set Lambda timeout: 25s
# SQS visibility timeout: 30s → Lambda timeout: 25s
# Never set timeout to maximum (900s) unless needed
# Memory tip: memory also controls network bandwidth and CPU
# 1769MB = 1 full vCPU (below this: fractional CPU)Provisioned concurrency for zero cold starts
# template.yaml (SAM)
Resources:
UserFacingApi:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs20.x
MemorySize: 512
Timeout: 25
AutoPublishAlias: live
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 10
# Application Auto Scaling for schedule-based PC:
# Scale up before peak, down after
# Saves cost vs always-on provisioned concurrencyX-Ray tracing — see distributed traces
const AWSXRay = require('aws-xray-sdk-core');
const AWS = AWSXRay.captureAWS(require('aws-sdk'));
// Now all AWS SDK calls are traced automatically
// Custom subsegments:
const segment = AWSXRay.getSegment();
const subseg = segment.addNewSubsegment('database-query');
try {
const result = await db.query(sql);
subseg.addAnnotation('rows', result.rowCount);
return result;
} catch(err) {
subseg.addError(err);
throw err;
} finally {
subseg.close();
}- ✅ Initialize DB/Redis/SDK clients outside handler
- ✅ Run Lambda Power Tuning before going production
- ✅ Provisioned Concurrency for user-facing p99 latency SLAs
- ✅ X-Ray for distributed tracing across Lambda+DynamoDB+SQS
- ✅ Layers for shared deps (reduces cold start and deployment size)
- ❌ Never set Lambda timeout to max without understanding downstream timeouts
- ❌ Never open DB connection inside handler loop
External reference: AWS Lambda operator guide.
Recommended Reading
→ Designing Data-Intensive Applications — The bible of distributed systems and production engineering at scale.
→ The Pragmatic Programmer — Timeless engineering wisdom every senior developer needs.
Affiliate links. We earn a small commission at no extra cost to you.
Related on CheatCoders: Lambda cold starts at zero cost, provisioned concurrency, SnapStart, and reserved concurrency, and LLM coding agents in Lambda sandboxes.
Free Weekly Newsletter
🚀 Join 2,000+ Senior Developers
Get expert-level JavaScript, Python, AWS, system design and AI secrets every week. Zero fluff, pure signal.
Related: AWS Clickstream Analytics at Massive Scale: Kinesis, Lambda, Firehose, S3, Athena, and OpenSearch in Production · AWS DynamoDB: Advanced Patterns for Production at Scale · AWS Lambda Layers: The Dependency Management Pattern You Should Be Using
Related: Lambda Durable Patterns: Avoid Step Functions Until Complexity Earns It · AWS Lambda SnapStart: Sub-100ms Cold Starts for Java Without Changing Your Code · How to Build a Hyper-Scale Serverless API Platform on AWS with API Gateway, Lambda, DynamoDB, and CloudFront
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Agentic Git Workflows: Atomic Commits From Noisy LLM Diffs
- Python String Methods: Every str Method With Real Production Examples
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
Newly added
- Amazon Bedrock Model Evaluation: Score Coding-Agent Outputs Before You Promote a Prompt
- AWS App Runner: Host Coding-Agent HTTP APIs Without Babysitting Containers
- Amazon S3 Object Lock: Immutable Artifact Buckets Coding Agents Cannot Overwrite
- AWS Security Hub: Aggregate Coding-Agent Security Findings Across Accounts
- Amazon Detective: Investigate Compromised Coding-Agent Credentials After GuardDuty
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
