Back to Blog
AWSCloudflarereduce_costsR2

Cloudflare for the AWS-native engineer

Past the "CDN vs CDN" framing: Cloudflare's anycast network, Workers versus Lambda@Edge, and why R2's zero-egress pricing quietly changes the math on bandwidth-heavy bills.

JohannaFebruary 18, 20266 min read

Most AWS-native engineers meet Cloudflare properly on the day a bandwidth line item stops being a rounding error. You have been living inside the AWS console, reaching for CloudFront when you need a CDN, and the comparison you have in your head is "one CDN versus another CDN." That framing hides the two things that actually matter: Cloudflare's network is architected differently from a traditional CDN, and its object storage charges nothing to serve data back out. If you only ever compare cache-hit ratios and TTLs, you will miss where the money is.

The network is the product

Cloudflare runs a single global anycast network. Every point of presence — a few hundred cities at last count — announces the same set of IP addresses via BGP, and the internet's own routing delivers a client to whichever PoP is closest in network terms. There is nothing clever running in the request path to "pick a region." The picking is done by BGP before the packet ever reaches Cloudflare.

The part that matters architecturally is that every PoP runs the full stack. DNS resolution, TLS termination, the WAF, the cache, and the Workers compute runtime all live in every data center. There is no tier of small edge nodes that proxy back to a handful of big ones for the interesting work. This is the real contrast with CloudFront, which has a large fleet of edge locations for caching but only runs Lambda@Edge at a smaller set of regional edge caches, and restricts its lightweight CloudFront Functions to header-manipulation-grade JavaScript with no network access. On Cloudflare, the same code and the same security policy execute in the same place the bytes are cached.

Workers and Lambda@Edge are not the same shape

This is where the two platforms diverge most sharply, and it is worth understanding the mechanism rather than the marketing.

Lambda@Edge is Lambda. Each invocation runs in a firecracker microVM with its own filesystem, its own runtime, and a cold start you pay for in latency when a fresh environment spins up. You get a real Node or Python runtime, generous memory, and multi-second execution budgets. That capability costs weight: heavier cold starts, and it only runs at regional edge caches, not at every edge location.

Cloudflare Workers use V8 isolates instead of containers. An isolate is the same primitive a browser tab uses to sandbox a site: a lightweight memory boundary inside a single shared process, so one process can hold thousands of them. There is no per-request container to boot. Cold start is on the order of single-digit milliseconds because "starting" a Worker is mostly just handing the request to an already-warm V8 with your script loaded. The tradeoff is a constrained runtime — you get web-standard APIs, tight CPU-time limits per request, and no arbitrary native binaries. For request routing, auth checks, header rewriting, A/B logic, and stitching together backend calls, isolates are the better fit. For heavy compute or a full legacy Node runtime, Lambda@Edge's container model still wins.

If you have been reaching for Lambda@Edge to do things like signed-cookie validation or path rewriting, that is exactly the workload isolates were built for, and you will feel the latency difference.

The egress problem, stated in one number

Now the money. AWS charges you to move data out to the internet. In us-east-1 the first tier runs around $0.09 per GB, softening as you cross volume thresholds (the first 10 TB tier, then cheaper bands above 10 TB, 50 TB, 150 TB), and the exact numbers vary by region. Inbound is free. Cross-service traffic inside the same region is often free or cheap. But the public egress — the bytes your users actually download — is billed at that per-GB rate, and for anything media-heavy it silently becomes the largest line on the bill.

Run the arithmetic once and it sticks. A site serving 100 TB of images and video a month out of S3, at roughly $0.085/GB blended after the tier discounts, is around $8,500 a month in egress alone. The storage for those objects might be a few hundred dollars. You are paying an order of magnitude more to hand out the data than to keep it.

R2 and the zero-egress claim

Cloudflare R2 is an S3-compatible object store whose pricing inverts that model: you pay for storage (roughly $0.015 per GB-month) and for operations (Class A writes/lists and Class B reads, priced per million requests), and $0 for egress. Serving the data costs nothing per gigabyte. The API speaks the S3 dialect — same PutObject/GetObject verbs, same multipart upload, same presigned URLs — so most SDKs work by changing an endpoint and credentials rather than rewriting your data layer.

That single change, for the 100 TB example above, takes egress from ~$8,500 to $0 and replaces it with ~$1,500 of storage plus operation charges. The catch is that R2's operation pricing rewards large objects read whole and punishes workloads that hammer millions of tiny objects; do the per-request math for your access pattern, not just the per-GB math.

When fronting S3 with Cloudflare actually helps

Here is a nuance people get wrong: AWS is not part of Cloudflare's Bandwidth Alliance, the arrangement where partner clouds waive or discount egress to Cloudflare. So if you keep data in S3 and put Cloudflare in front, every cache miss still pulls from S3 and you still pay AWS $0.09/GB for that fetch. What you save is on cache hits: bytes Cloudflare serves from its own cache never touch S3 and cost you nothing in AWS egress.

That makes cache-hit ratio the whole game. A catalog of hot, cacheable objects — product images, a static site, popular video segments — might run a 95%+ hit ratio, so you pay AWS egress on only the 5% that misses and Cloudflare serves the rest for free. Fronting S3 is a genuinely good move there, and it requires no data migration.

It stops helping when the object set is enormous and access is long-tailed (every request is effectively a miss), or when content is dynamic and uncacheable. In those cases the cache is a pass-through and you are paying full S3 egress plus complexity. That is the signal to actually migrate hot objects to R2 rather than cache them: R2 removes the egress charge at the source instead of trying to dodge it downstream.

When none of this is worth it

Egress optimization is only worth engineering effort when egress is a real number. If you are moving a terabyte a month, your egress is under a hundred dollars and you should spend your attention elsewhere — the migration and dual-write complexity will cost more than you save. Tight coupling is the other brake: if the objects feed Athena, Rekognition, or a Glue pipeline, pulling them out of S3 to save egress can cost you more in cross-cloud transfer and integration than you recover. And regulated data with residency or audit constraints may simply have to stay in a specific AWS region.

The honest summary: Cloudflare's edge is a different machine than CloudFront's, worth understanding on its own terms, and R2 is the rare pricing change that can move a bandwidth bill by an order of magnitude — but only for the workloads where bandwidth was the bill in the first place. Measure your egress and your cache-hit ratio before you touch anything. Those two numbers tell you whether there is money on the table at all.