DEV Community

Cover image for AWS Lambda Looks Cheap Until the Whole Bill Arrives
Jaya Prakash Edala
Jaya Prakash Edala

Posted on

AWS Lambda Looks Cheap Until the Whole Bill Arrives

A team moves a batch job from EC2 to Lambda to kill an idle server. Compute cost drops. Then API Gateway charges climb, CloudWatch Logs ingestion grows, and a traffic spike drives more concurrent database connections than RDS can handle.

WHAT

Lambda is event-driven compute where AWS owns the host, OS, and scaling layer, and billing is per request plus per millisecond of memory-weighted runtime.

  • Triggers: S3, API Gateway, SQS, EventBridge, direct invoke
  • Memory: 128 MB to 10,240 MB. CPU scales with memory, so tuning moves both speed and cost
  • Time limit: 15 minutes per invocation
  • Concurrency: Reserved concurrency sets a function's concurrency limit and reserves capacity for it. Provisioned concurrency keeps environments initialized to reduce cold-start latency, at added cost
  • Access: The IAM execution role defines what the function can touch

WHERE

Lambda runs wherever work is triggered by an event rather than a continuous process.

  • API backends: API Gateway receives the request, Lambda runs the logic, DynamoDB or RDS stores the result.
  • File processing: S3 uploads trigger resizing, validation, or data transformation.
  • Queue consumers: SQS buffers work, Lambda processes messages.
  • Scheduled automation: EventBridge triggers jobs and reacts to events across AWS services.

Each part of the request path brings its own charges and limits. API Gateway adds request costs, SQS adds queue and request costs, RDS has finite connection capacity, and CloudWatch cost follows log volume and retention. The estimate covers the entire request path, not just the function.

WHY

Two costs shrink: idle compute and infrastructure management. An instance sized for peak demand bills around the clock while barely used. Lambda bills for execution. Patching and fleet management also leave the runbook, which often matters more to a small team than the compute discount.

The cost is predictability. Spending now follows traffic, execution duration, retries, and application behavior.

The function isn't the only cost driver. API Gateway requests, CloudWatch Logs ingestion, data transfer, and NAT Gateway processing for VPC-attached functions each add substantial charges. A function stuck in a retry loop keeps billing without finishing any work.

Estimate every service on the request path in the AWS Pricing Calculator, not just Lambda.

WHEN

Deploy Lambda when:

  • Traffic has long quiet gaps and sharp bursts
  • Each task finishes well inside the 15-minute limit
  • Demand is hard to forecast, so fixed capacity would sit idle
  • The team does not want to run a compute fleet

Avoid or look out for:

  • Steady, high utilization. Constant load often favors ECS on Fargate or EC2 with a Savings Plan. Price both with realistic traffic.
  • Latency-sensitive paths. Cold starts can increase response times. Provisioned concurrency reduces cold-start latency, but adds cost.
  • Database saturation. Lambda can scale beyond the connection capacity of RDS. Manage connections, limit concurrency, or buffer work with a queue.
  • Jobs over 15 minutes. Move to containers or another compute option built for long-running work.
  • Duplicate delivery. Events can arrive more than once. Payments and database updates need idempotent handling.

HOW

Scenario: product image pipeline for an e-commerce catalog.

Sellers upload product images. Each image must be resized, stored, and reflected in the catalog database. The obvious design connects S3 directly to Lambda. The open question: what happens when thousands of images arrive at once?

Direct S3-to-Lambda invocation can produce a burst of concurrent executions, each potentially writing to the catalog database. If those operations exceed database capacity, connection exhaustion hits the wider application.

SQS adds a buffer, but the queue alone does not protect the database. Lambda's maximum concurrency must also be configured to match the database's available capacity.

NAIVE DESIGN
Upload -> S3 -> Lambda -> RDS
          (a burst of concurrent executions
           can overwhelm the database)

BUFFERED DESIGN
Upload -> S3 (incoming/) -> SQS Standard queue
                              |
                              v
                            Lambda
                         (concurrency limit)
                              |
                 +------------+------------+
                 |                         |
                 v                         v
          S3 (processed/)            RDS (catalog)

FAILURE PATH (separate from the normal flow)
SQS Standard queue --[exceeds redrive policy limit]--> DLQ

CloudWatch: logs, metrics, alarms
Enter fullscreen mode Exit fullscreen mode
  1. A seller uploads an image to incoming/ in S3.
  2. S3 sends an object-created notification to an SQS Standard queue. S3 event notifications cannot target FIFO queues directly.
  3. Lambda polls the queue with maximum concurrency configured to match the database's available capacity.
  4. The function resizes the image, writes it to processed/, and updates the catalog.
  5. Messages that keep failing move to the dead-letter queue per the redrive policy.
  6. CloudWatch alarms fire on errors, queue depth, and message age.

Pre-launch checks:

  • Separate input and output paths. Writing back to the trigger location creates a recursive loop.
  • Scope the IAM role. Read on source, write on destination, plus only the downstream access required.
  • Set the visibility timeout. For an SQS event source mapping, AWS recommends at least six times the function timeout, plus the batching window if one is configured.
  • Make processing idempotent. Standard queues provide at-least-once delivery, so duplicate processing is possible. Processing the same image twice must leave no duplicate side effects.
  • Handle partial failures. A database write can succeed before Lambda fails, and the message then retries. Use idempotency keys or conditional writes so a retry cannot duplicate side effects or corrupt the catalog.
  • Set maximum concurrency from real capacity figures. Account for RDS capacity, connections per invocation, execution duration, and competing workloads sharing the database. The connection limit is only the starting point. Validate under realistic load.
  • Monitor the backlog and run a spike test. Track queue depth and message age. Confirm the queue absorbs the burst, the database stays healthy, and failed messages are recoverable. A single-image demo proves none of that.

SQS adds cost. That cost buys buffering and separates incoming traffic from processing capacity. The concurrency limit helps control how quickly Lambda processes the backlog.

TAKEAWAY

Lambda removes the server, not the responsibility: price the full request path, match concurrency to downstream capacity, and design for retries before the first deploy.

Top comments (0)