One container, three platforms: Cloud Run vs. ECS Express Mode vs. Lambda
Running a small HTTP application in a container sounds straightforward. Choosing where to run it is less obvious: Google Cloud Run, AWS ECS Express Mode, and AWS Lambda can all expose the same application over HTTPS, but their execution models—and their idle costs—are quite different.
This post compares execution models, proxy placement, and modeled costs for a small HTTP workload. It is a comparison of specific configurations, not a performance benchmark or a report of measured bills.
The same application, different execution models
Cloud Run and ECS run the application as a conventional HTTP server. Lambda takes a different path: the image includes Lambda Web Adapter, which translates invocation events into HTTP requests to the application. Cloud Run and ECS run the app directly without starting that extension.
The application is shared, but the resources are not identical:
| Cloud Run | ECS Express Mode | Lambda | |
|---|---|---|---|
| CPU / memory | 1 vCPU / 2000 MiB | 1 vCPU / 2048 MiB | CPU proportional to memory / 2048 MiB |
| Compute model | Scales from zero to one instance | One continuously running Fargate task | On-demand execution environments, without provisioned concurrency |
| HTTPS endpoint | Managed service URL | Managed endpoint through an Application Load Balancer | Function URL |
| HTTP integration | Native HTTP server | Native HTTP server | Lambda Web Adapter; 15-second invocation timeout |
Cloud Run stores its image in Artifact Registry; ECS and Lambda share an ECR repository and image URI.
The important distinction is what happens when no requests arrive. Cloud Run can scale to zero. Lambda has no provisioned compute in this configuration. ECS keeps its task running, along with the load balancer and public IPv4 addresses. Scaling to zero does not eliminate every possible charge—image storage and logging can still cost money—but it changes the baseline substantially.
What does a replica mean?
The platforms use different names for related concepts, and those names are not interchangeable.
On ECS, the running replica is a task. An ECS service maintains the desired number of tasks.
On Cloud Run, the running replica is a service instance. The service manages and scales those instances.
On Lambda, the closest equivalent is an execution environment. Standard on-demand Lambda handles one invocation at a time per environment.
Each replica in this comparison contains one application container. ECS tasks and Cloud Run instances can contain separately configured sidecars. Lambda accepts one image per function rather than a multi-container sidecar configuration, although that image can run multiple processes.
Performance and deployment caveats
Sharing an image does not make these configurations equivalent performance tests. Cloud Run and Lambda may cold-start, while the ECS task stays running. Lambda’s CPU allocation depends on memory, and its invocation model differs from a conventional HTTP server.
Lambda’s buffered Function URL also has a 6 MB response limit; larger responses would need separate consideration.
ECS Express Mode provides managed HTTPS, but this configuration still depends on an existing default VPC with public default subnets in at least two Availability Zones, internet-gateway routes, and DNS enabled. Its task, ALB, and public IPv4 addresses continue incurring charges while provisioned.
What changes when we add a proxy?
A proxy can handle cross-cutting concerns for an HTTP service: routing, authentication, traffic controls, timeout management, and request or response transformations. Which capabilities are available depends on the proxy and its configuration. This introduces another choice: colocate the proxy alongside the application, or use a separate gateway in front of it. The following options are architectural alternatives; their modeled costs are compared near the end of this post.
A proxy alongside the application
The request path becomes client → platform endpoint → proxy → application. A proxy such as Nginx or Envoy can apply routing rules, manage upstream connections, and process requests or responses without putting that logic in the application. Some capabilities require additional modules or external services.
| Platform | Proxy arrangement | Effect on the comparison |
|---|---|---|
| Cloud Run | Proxy as the ingress container; application as a sidecar reached over localhost. | Still scales to zero, but additional container resources and processing can increase billing. |
| ECS Express Mode | Proxy and application in the same Fargate task, using a custom task definition. | Reuses the existing ALB. Compute cost stays unchanged if both fit the current task allocation. |
| Lambda | Proxy and application as processes inside one image; Web Adapter forwards to the proxy. | Possible, but adds process management and startup overhead rather than an independently configured sidecar. |
Cloud Run and ECS are the more natural fits for this arrangement. A colocated proxy shares the application’s scaling and deployment lifecycle: each replica runs its own proxy, and requests have already reached the application’s compute allocation before the proxy handles them.
A separate gateway
The request path becomes client → gateway → application, potentially through a platform endpoint between the gateway and the application. For ECS, the existing ALB serves as both the gateway and the platform endpoint; no additional load balancer is needed. This moves shared request handling outside the application’s replica lifecycle. Depending on its capabilities, the gateway can route, authenticate, transform, or reject requests before they reach the application.
| Platform | Managed option | Cost implications |
|---|---|---|
| Cloud Run | External Application Load Balancer, optionally paired with Cloud Armor. | Adds load-balancer charges and, if enabled, security-policy charges. |
| ECS Express Mode | Existing ALB, optionally paired with AWS WAF. | Reuses the ALB already included in the estimate; WAF adds separate charges. |
| Lambda | CloudFront, optionally paired with AWS WAF and edge processing. | Adds a front-door layer; requests handled there need not invoke Lambda. |
These are not interchangeable, general-purpose proxies. Each offers a different set of routing, security, and request or response controls, with limits on what can be configured. Some capabilities require additional integrations or custom code.
A self-hosted gateway is another option. It provides more control over proxy behavior, but requires its own compute and availability planning. Using the same external gateway with all three platforms would make the feature comparison more uniform, while retaining their different compute models.
State, identity, and bypass protection
The placement of a proxy does not by itself guarantee consistent policies. Stateless rules are relatively straightforward to distribute across replicas, but features such as service-wide quotas need coordination. Local rate-limit counters can differ between replicas and reset on restart; Lambda’s execution environments make that local state particularly unreliable. AWS WAF and Cloud Armor also provide approximate abuse controls, not exact quotas.
Strict quotas require coordinated counters and a precisely defined enforcement policy. A shared store or external policy service can provide coordination, but introduces cost, request latency, and a failure-policy decision: what should the proxy do when that dependency is unavailable?
Behind a gateway, the socket peer is usually another proxy. Use platform-provided client-IP metadata or a correctly configured trusted-proxy chain, not arbitrary client-supplied X-Forwarded-For values. Likewise, identity passed by a gateway should only be trusted when clients cannot forge it or bypass the gateway’s checks.
If the gateway enforces required policies, the original endpoint must be protected against direct access. Cloud Run needs appropriate ingress restrictions, ECS needs appropriate network access controls, and Lambda Function URLs can use CloudFront origin access control with IAM authorization.
For lightweight request handling at low cost, a colocated Cloud Run proxy—or application middleware if a separate component is unnecessary—is a straightforward choice. A separate gateway is useful when policies should be independent of application replicas or enforced before requests reach application compute. ECS benefits from already having an ALB, while Cloud Run and Lambda need an additional front-door layer in these arrangements. In either case, gateway and supporting-service costs can outweigh application compute, so an application-only estimate does not capture the full architecture.
A small workload makes the cost difference visible
The monthly estimate assumes a steady, modest workload:
- 10 requests per minute for 730 hours: 438,000 requests.
- 100 ms total billed duration per request: 43,800 seconds of processing.
- 100 KB per response: 43.8 GB, or about 40.8 GiB, of response data.
Cloud Run uses request-based billing with zero minimum instances. Lambda runs on demand without provisioned concurrency. ECS runs continuously maintaining one task, with a dedicated ALB across three Availability Zones and four public IPv4 addresses: three for the ALB and one for the task.
App only, colocated proxy, or managed gateway
Estimated monthly costs in USD, before recurring free allowances, promotional credits, and taxes:
| Platform | App only | App + colocated proxy | App + managed gateway |
|---|---|---|---|
| Cloud Run | $6.34 | $7.40 | $32.24 |
| Lambda | $5.22 | $5.22 | $11.81 |
| ECS Express Mode | $75.70 | $75.70 | $81.96 |
These are three alternative configurations, not cumulative additions. The proxy columns price a narrow example: supported static header changes and per-IP limiting. They are not estimates for every capability discussed above or feature-equivalent proxy deployments. Authentication services, shared state, and custom processing are excluded.
Colocated proxy assumptions: Cloud Run keeps the application’s allocation and adds an illustrative 1 vCPU / 128 MiB proxy container, costing about $1.06 in additional request-time compute. This is a budgeting choice, not a minimum proxy requirement. ECS fits the proxy into its existing 1 vCPU / 2048 MiB task, and Lambda keeps its existing 2048 MiB allocation. All three retain the modeled 100 ms total billed duration, including the proxy. Actual proxy overhead has not been measured: longer duration or larger resource allocations would change these estimates.
Where the money goes
The app-only estimates break down as follows:
- Cloud Run: $1.44 for compute and requests, plus $4.90 for internet egress.
- Lambda: $1.55 for compute and requests, plus $3.67 for internet egress.
- ECS: $39.64 for Fargate, $17.48 for the ALB, $14.60 for public IPv4, approximately $0.31 for ALB capacity, and $3.67 for egress. Express Mode adds no separate fee.
The managed-gateway column uses these specific arrangements:
- Cloud Run — global external Application Load Balancer + Cloud Armor Standard: about $18.25 for forwarding rules at $0.025/hour, $0.33 for response-data processing at $0.008/GiB, and $7.33 for one security policy, two rules (rate limit and default), and 438,000 requests. Internet egress remains approximately $4.90; it is not charged again as separate Cloud Run egress. The total uses unrounded calculations.
- ECS — AWS WAF on the existing ALB: adds about $6.26: $5 for one web ACL, $1 for one rate-based rule, and $0.26 for requests at $0.60/million. The ALB is already in the baseline; supported ALB header modification does not require another proxy service.
- Lambda — CloudFront + AWS WAF, pay-as-you-go: $1.55 for Lambda compute and requests, $6.26 for WAF, about $0.53 for European HTTPS requests at $0.012/10,000, and $3.47 for response delivery at $0.085/GB using AWS’s binary billing units. CloudFront delivery replaces the direct Lambda internet-egress estimate; AWS-origin transfer to CloudFront is free. Static response-header policies are assumed, with no paid edge-function execution.
Recurring allowances can materially reduce these totals. In particular, unused CloudFront allowances cover this modeled request volume and response traffic. CloudFront also offers flat-rate plans, including a free plan with bundled WAF; those are separate pricing alternatives, not the pay-as-you-go configuration modeled here.
The estimates exclude logs and alarms, image storage, DNS, request and header overhead, cold starts, deployment overhead, shared counter storage, and additional security features. These are workload estimates rather than measured bills; pricing and eligibility can change.
At this traffic level, ECS’s continuously provisioned infrastructure still dominates its cost. A managed gateway adds a much larger proportional expense to Cloud Run and Lambda, while a colocated proxy can be inexpensive if it fits the modeled resources and duration.
The takeaway
The same container can run on all three, but that does not make them equally natural fits. My default choices would be:
- Lambda for standalone code functions: use it for bounded, request- or event-driven work. Container images are a supported packaging format, not a conventional container-hosting model. Running an HTTP server through Web Adapter works, but introduces an adaptation layer and retains Lambda’s invocation timeouts, read-only filesystem outside
/tmp, and execution-environment lifecycle. Prefer function-shaped code rather than choosing Lambda just because it accepts an image. - Cloud Run for self-contained, independently deployed container services: use it when the application is a conventional HTTP server and you want managed serving and scale-to-zero without managing a cluster. A colocated proxy or sidecar fits naturally. Service-to-service communication is possible, but synchronous calls go through the destination service’s HTTP endpoint, typically with an OIDC identity token and IAM permissions for authenticated access. That is a different model from a cluster’s internal service discovery and networking.
- ECS for a networked set of interacting container services: use it when you want more control over task placement, networking, service discovery, and long-running processes. With Service Connect configured, services can reach each other using short service names, making ECS a more natural fit for this architecture. ECS also runs standalone services; a multi-service architecture is a reason to consider it, not a requirement. Express Mode simplifies deploying HTTP services, while the broader ECS platform offers more control for complex arrangements.
These are architectural defaults, not hard boundaries. Choose based on the execution and networking model you need, not just the image format.