AWS Lambda is often praised for its pay-per-use model, where you are billed only for the compute time your code consumes. At $0.0000166667 per GB-second, a single invocation lasting 100 milliseconds with 128 MB of memory costs roughly $0.000000213. That is so small that many developers treat it as effectively free. But as any seasoned serverless engineer will tell you, the real cost of Lambda is not always in the compute time. There are other charges—some obvious, some buried in the fine print—that can turn a seemingly cheap function into a steady drain on your monthly budget. This article walks through the components that add up to that fractional cent per invocation, using concrete examples and hedged numbers. By the end, you will have a clear picture of where your money goes and a few practical ways to keep it from leaking.
The Lambda That Costs More Than It Earns
Consider a low-traffic function that handles occasional webhook events. It runs for about 100 milliseconds on average, using the default 128 MB of memory. AWS Lambda rounds up the duration to the nearest millisecond, so a 100 ms invocation is billed as 101 ms. The cost per invocation is roughly $0.000000213. At 100,000 invocations per month, that is about $0.02 in compute. Not bad. But the same function may incur cold start overhead. Cold starts add latency—sometimes 200 ms or more—and that extra time is billed. Even more, the function may be invoked only a few times per hour, meaning it idles most of the day, yet you still pay for each invocation. The real kicker is that low-traffic functions often never break even when you factor in the engineering time to maintain them. The economics of Lambda favor high-volume, bursty workloads. A function that runs a few hundred times a month may cost pennies in compute but hours in debugging and deployment effort. Some teams have found that moving such functions to a simple cron job on a low-cost EC2 instance is cheaper overall, especially when you consider the operational overhead. For example, a team at a mid-sized e-commerce company migrated a low-traffic inventory sync function from Lambda to a t4g.nano instance running a cron job, reducing their monthly infrastructure cost from $5.30 (including NAT Gateway share) to $3.50, and cutting maintenance time by two hours per month. However, this trade-off requires accepting a fixed server cost and managing the instance's uptime, which might not suit teams that prefer fully managed services. Another counter-argument is that the engineering time to set up and monitor the EC2 instance could offset the savings, especially if the team lacks DevOps expertise. The key is to evaluate the total cost of ownership, including labor, for each low-traffic function.
Why Your Provisioned Concurrency Bill Is a Gamble
Provisioned concurrency keeps a set number of Lambda environments warm and ready to serve requests instantly, eliminating cold starts. The trade-off is that you pay for the time those environments are allocated, even if they are not handling requests. The cost is $0.0000041667 per GB-hour for provisioned concurrency, on top of the standard compute charges when invocations occur. For a 1 GB function with 10 provisioned concurrent executions running 24/7, the monthly cost is roughly $36.50—just for keeping them warm. That might be acceptable for a latency-sensitive API where a 200 ms cold start would break the user experience. But if traffic drops unexpectedly—say, a marketing campaign ends or a partner stops sending events—you are stuck paying for idle capacity. Reserved concurrency, on the other hand, is free but only caps the number of concurrent executions; it does not prevent cold starts. The gamble with provisioned concurrency is that you are betting on a predictable traffic pattern. If your traffic is spiky or seasonal, you may need to use auto-scaling with scheduled actions, which adds complexity. Some teams prefer to accept cold starts for non-critical endpoints and reserve provisioned concurrency only for the hot path. As of late 2024, AWS offers a pricing model where you pay for provisioned concurrency only when it is allocated, but you still pay for idle time. The key is to monitor utilization and adjust allocations dynamically, perhaps using Application Auto Scaling with target tracking. Even then, the cost can surprise you if you over-provision. For instance, a fintech startup provisioned 50 concurrent executions for their authentication function to ensure sub-100 ms response times. After a traffic analysis, they discovered that peak concurrency never exceeded 30, and they were paying $146 per month for idle capacity. By reducing provisioned concurrency to 35 and enabling auto-scaling, they cut costs by 30% while maintaining performance. However, this approach requires continuous monitoring and may introduce complexity in scaling policies. A counter-argument is that the engineering effort to fine-tune provisioned concurrency could be better spent on optimizing cold starts through SnapStart or increased memory, which are simpler to implement.
The Hidden Cost of VPC Networking
When you connect a Lambda function to a VPC, it loses direct internet access and must route traffic through a NAT Gateway or a VPC endpoint. NAT Gateway charges $0.045 per hour plus $0.045 per GB of data processed. Each invocation that accesses the internet—say, to call an external API—incurs NAT Gateway costs, even for tiny payloads. A function that makes a 10 KB request to an external service will be billed for the data transfer through the NAT Gateway. At 1 million invocations per month, each transferring 10 KB out and 10 KB in, the data volume is about 20 GB. That adds roughly $0.90 in NAT data processing fees, plus the hourly cost of the NAT Gateway itself (about $32.40 per month if running 24/7). The total extra comes to around $33 per month, or about $0.000033 per invocation—far more than the compute cost. Cross-AZ data transfer can also sneak up on you. If your Lambda function and its database are in different availability zones, you pay $0.01 per GB for data transfer between them. For a chatty application, that can add up quickly. One way to mitigate this is to place Lambda in the same AZ as its dependencies, or use VPC endpoints for services like S3 and DynamoDB, which bypass the NAT Gateway. Another approach is to avoid VPC entirely by using AWS Lambda's public IP mode for functions that do not need to access private resources. But if you must use VPC, be prepared for a bill that is often dominated by networking costs, not compute. Consider a real-world scenario: a media processing pipeline that resizes images and stores them in S3 used a VPC with a NAT Gateway for internet access. The team found that the NAT Gateway cost was $45 per month, while the Lambda compute cost was only $12. By switching to a VPC endpoint for S3 and using a proxy Lambda in a public subnet for external API calls, they reduced networking costs to $8 per month. However, this added architectural complexity and required maintaining two Lambda functions. A counter-argument is that for functions with low invocation volume, the NAT Gateway cost is amortized across all functions in the VPC, making it less significant per function. The trade-off between simplicity and cost must be evaluated per use case.
Ephemeral Storage: The 512 MB Ceiling That Pinches
Every Lambda function gets 512 MB of ephemeral storage in /tmp at no extra cost. This is sufficient for many use cases, but if your function needs to download large models, process heavy log files, or generate temporary artifacts, you may need more. AWS allows you to allocate up to 10 GB of ephemeral storage, but it comes at a cost: $0.0000000308 per GB-second. For a function with 2 GB of storage and an average duration of 10 seconds, the storage cost per invocation is about $0.000000616. That is negligible for a few thousand invocations, but at scale it adds up. Consider a data processing pipeline that runs 10 million invocations per month, each using 2 GB of storage for 10 seconds. The storage cost alone would be roughly $6.16 per month—still small but not zero. The bigger issue is that the 512 MB ceiling can force you to use more memory than you need, because Lambda's memory allocation also determines CPU power. If your function is I/O-bound and needs more storage, you might be tempted to increase memory just to get more CPU, which inflates compute costs. A better approach is to stream data to S3 or use a sidecar container with EFS, which adds complexity but can be cheaper. Some teams have found that the ephemeral storage cost is often the least significant, but it can become a bottleneck for data-intensive workloads. As of early 2025, AWS has not changed the pricing for ephemeral storage, so it remains a minor but real factor in your Lambda bill. For example, a machine learning inference function that loads a 1.5 GB model into /tmp incurred an additional $0.000000462 per invocation for storage. At 500,000 invocations per month, that added $0.23 to the bill. While trivial, the team realized that increasing memory to 3 GB to get more CPU also increased compute cost by $2.10 per month. By optimizing the model to fit within 512 MB through quantization, they avoided both extra costs. This trade-off between storage and memory highlights the need to profile your function's resource usage. A counter-argument is that for functions with unpredictable storage needs, allocating extra storage is simpler than refactoring code, and the cost is often negligible compared to developer time.
How X-Ray and Logging Inflate Your Bill
AWS X-Ray tracing and CloudWatch Logs are optional but commonly enabled for debugging and monitoring. X-Ray charges $0.0000005 per trace recorded and $0.00000005 per segment scanned. For a function that generates one trace per invocation and scans a few segments, the cost is roughly $0.0000006 per invocation. At 10 million invocations, that is $6 per month. CloudWatch Logs charges $0.50 per GB ingested and $0.03 per GB archived. A function that logs 1 KB per invocation will ingest about 10 GB per month at 10 million invocations, costing $5 for ingestion and about $0.30 for archiving. Combined, logging and tracing can add $11.30 per month, or about $0.00000113 per invocation. That is still small, but it can double the per-invocation cost for a lightweight function. The problem is that many teams leave verbose logging enabled in production, logging every input and output. A single log line can easily be 500 bytes, and with multiple log statements per invocation, the log volume multiplies. A practical tactic is to disable X-Ray tracing for functions with low error rates and to use structured logging with a minimum level set to ERROR in production. You can also set log retention to 7 days and export logs to S3 for cheaper archival. Some teams use a log aggregator like Datadog or New Relic, which shifts the cost but does not eliminate it. The key is to be intentional about what you log and trace, because those fractional cents add up across millions of invocations. For instance, a SaaS company discovered that their logging costs for a high-traffic API function were $23 per month, while the compute cost was only $8. By switching from logging full request/response bodies to logging only request IDs and error codes, they reduced log volume by 80% and saved $18 per month. However, this reduced their ability to debug issues in production, so they implemented a separate debug mode that could be toggled for specific users. This trade-off between observability and cost is common in serverless architectures. A counter-argument is that the cost of missing a critical bug due to insufficient logging can far exceed the savings, so teams should prioritize logging for critical paths and accept the cost.
Benchmarking a Real-World Image Resizer
To ground these numbers, consider a typical image resizing function built with the Sharp library. It receives a 100 KB JPEG, resizes it to 50 KB, and returns the result. On average, the function runs for 250 milliseconds and uses 256 MB of memory. At $0.0000166667 per GB-second, the compute cost per invocation is roughly $0.00000104. For 1 million invocations per month, that is about $1.04. CloudWatch Logs add another $0.50 for 1 KB per invocation, totaling $1.54. If the function is VPC-enabled and accesses an S3 bucket via NAT Gateway, the NAT Gateway hourly cost ($32.40) plus data transfer ($0.90 for 20 GB) adds approximately $33.30, but that is shared across many functions. For this single function, a fair share might be $10 per month. So the total monthly cost is around $11.54, or about $0.000001154 per invocation. That is still less than a tenth of a cent per call, but it is an order of magnitude higher than the raw compute cost. The image resizer is a good candidate for optimization: you could reduce memory to 128 MB if the resize is not CPU-bound, or use S3 event notifications to trigger the function only when needed. The numbers show that for a moderate-traffic function, the cost is manageable, but the hidden costs—especially VPC—can dominate. This example also highlights that per-invocation cost is a useful metric, but the total monthly cost is what matters for budgeting. To further illustrate, consider a variant where the function uses 512 MB of memory and runs for 200 ms due to better CPU performance. The compute cost becomes $0.00000178 per invocation, slightly higher, but the total cost might be lower if it reduces cold starts. A/B testing different memory allocations can reveal the sweet spot. Another trade-off is using a Graviton2-based function, which reduces compute cost by about 20% to $0.000000832 per invocation, saving $0.21 per month at 1 million invocations. While small, these savings compound across multiple functions. The image resizer example demonstrates that detailed benchmarking is essential to identify cost drivers that are not immediately obvious from the pricing page.
Three Tactics to Shave the Fractional Cent
First, right-size your memory allocation. Lambda's pricing is linear with memory, but CPU power scales with memory up to a point. For compute-bound functions, increasing memory can reduce duration and lower total cost. The sweet spot for many workloads is around 1769 MB, which provides full CPU power. Use AWS Lambda Power Tuning to find the optimal memory for your function. For example, a data transformation function that originally used 128 MB and ran for 3 seconds was optimized to 512 MB, reducing duration to 800 ms and cutting compute cost by 37%. Second, use Lambda SnapStart for Java functions. SnapStart reduces cold start latency by roughly 90%, which means you can often avoid provisioned concurrency and its associated costs. As of early 2025, SnapStart is available for Java 11 and later, and it can be enabled with a single toggle. A Java-based order processing function that previously required 10 provisioned concurrent executions to meet latency SLAs was able to eliminate provisioned concurrency entirely after enabling SnapStart, saving $36.50 per month. However, SnapStart has limitations: it is not suitable for functions that require frequent code updates or have state that must be initialized at startup. Third, batch invocations using SQS or EventBridge. Instead of calling a Lambda function for each event, collect events and invoke the function in batches. This reduces the number of invocations and the associated costs for logging, tracing, and VPC networking. For example, a function that processes 100 events per invocation instead of 1 will see a 99% reduction in invocation count. A real-world case: a clickstream analytics pipeline reduced its Lambda invocations from 5 million to 50,000 per month by batching, cutting total cost from $120 to $15. The trade-off is increased latency for individual events, which may not be acceptable for real-time applications. Additionally, consider switching to ARM64 (Graviton2) architecture, which offers roughly 20% lower cost than x86 for the same performance. Many runtimes, including Node.js, Python, and Java, support ARM64 natively. A migration from x86 to ARM64 for a set of 10 functions resulted in a 22% cost reduction without any performance degradation. Finally, monitor your costs with AWS Cost Explorer and set budgets to alert you when costs exceed thresholds. A small monthly review of Lambda costs can catch unexpected spikes before they become a surprise. These tactics are not silver bullets, but they can collectively reduce your Lambda bill by 30–50% for typical workloads. The key is to understand your specific usage pattern and apply the right mix of optimizations. For instance, combining memory right-sizing, SnapStart, and batching can yield synergistic savings, as each optimization targets a different cost component. However, implementing all three may require significant refactoring, so prioritize based on the biggest cost drivers identified through monitoring. A counter-argument is that the engineering effort to implement these optimizations may outweigh the savings for small-scale deployments. In such cases, a simpler approach like setting a monthly budget and using AWS Compute Optimizer can provide a good balance between cost and complexity.