Vylara
awscostarchitecture

S3 vs CDN: Where Your Static Assets Should Actually Live

S3 stores your static files; a CDN caches them at the edge. You almost always want both. Here's the honest cost and latency breakdown for a small team.

Written byVylara Team
5 min read
S3 vs CDN for Static Assets

S3 and a CDN solve different problems, and for most apps you want both. S3 is durable object storage — the authoritative home for your images, uploads, and build artifacts. A CDN (on AWS that’s CloudFront) is a cache layer that copies those objects to edge locations near your users, so a request from Sydney doesn’t round-trip to us-east-1. Serving directly from S3 works, but you pay a latency and egress tax for it. The right mental model is simple: S3 is the origin, the CDN is the delivery. Choose S3-only when traffic is tiny and local; add a CDN the moment you have global users or bandwidth that matters.

What each one actually does #

S3 gives you eleven nines of durability and costs about $0.023 per GB per month in standard storage. That’s the cheap part. The expensive part is getting bytes out: S3 data transfer to the internet runs roughly $0.09 per GB after the first free gigabyte. A single viral asset or an unoptimized image gallery can turn that into a real line item fast — the kind of surprise we catalogued in Anatomy of an AWS bill shock.

A CDN sits in front of S3 and caches responses at hundreds of edge locations. The win is twofold. First, latency: a cache hit is served from a city near your user, typically shaving 50–200ms off each request compared to a cross-region S3 fetch. Second, cost: CloudFront egress is often cheaper than S3 egress (around $0.085/GB in North America and Europe, less at committed volume), and every cache hit means your S3 origin is never touched, so you stop paying S3 request and transfer fees for repeat traffic.

The nuance people miss: a CDN doesn’t make your first request faster. A cache miss still pulls from the S3 origin, so the very first user in each region pays full origin latency. The benefit compounds as your cache hit ratio climbs — a well-configured static site routinely hits 90% or more, meaning nine out of ten requests never reach S3 at all.

When S3-only is genuinely fine #

If you’re serving a handful of internal assets to a team in one region, S3 with the right bucket policy is perfectly reasonable. At single-digit gigabytes of monthly transfer, your egress bill is pennies, and the operational simplicity of one fewer moving part is worth something. You also skip CDN cache-invalidation headaches — when you overwrite an object in S3, the new version is live immediately, whereas a CDN needs an invalidation (the first 1,000 per month are free on CloudFront, then about $0.005 each) or a cache-busting URL.

The flip side: serving a public bucket directly means exposing it to the internet, and public S3 buckets are a classic misconfiguration behind countless data leaks. If you go S3-only, keep the bucket private and front it with a signed-URL scheme or an application proxy rather than flipping on public read. Getting those permissions tight by hand is exactly the kind of chore that’s easy to get subtly wrong, and the failure mode is quiet rather than loud.

How Vylara handles this for you #

When you connect the Vylara GitHub App and the agent engine analyzes your repo, it looks for storage signals — an @aws-sdk/s3 import, multer, or a formidable upload handler — and surfaces a plain-language card: your app needs file storage, roughly $1/mo. You choose "Create a storage bucket" or "I already have one" and point it at an existing bucket. Nothing is provisioned on a git merge; the first deploy is what actually creates the S3 bucket in your own AWS account, with the connection details persisted so your service and the in-app chat reference the same URLs.

Because every resource lands in your account, the S3 egress and any CDN charges bill straight from AWS to you — Vylara never resells compute or bandwidth. That ownership model is the whole point of deploying without a DevOps team: you get the infrastructure a DevOps engineer would set up, in an account you fully control, and you can revoke access any time and keep everything.

The configs the agent generates are shown to you in a diff view with explanations before anything ships, and the bucket policies it produces default to private rather than public — the same philosophy we described in generating security groups from your code, where machine-written rules tend to end up tighter than the ones most teams write by hand. Be honest about the limit here: the agent’s initial sizing and storage class are a reasonable starting guess, not a tuned answer. Once real traffic shows up, the infrastructure chat can read your cost and transfer metrics and tell you whether you’ve grown into needing a CDN in front.

The decision, compressed #

Start with S3 as your origin — you need durable storage regardless. Stay S3-only while traffic is small and regional. Add CloudFront the moment any of three things become true: your users are spread across continents, your monthly egress climbs past a few tens of gigabytes, or you’re serving the same assets repeatedly enough that a 90% cache hit ratio would pay for itself. At that point the CDN isn’t an upgrade — it’s a cost reduction that also happens to make your app faster. The trap is adding it too early, before you have the traffic to justify the extra invalidation workflow, or too late, after an egress bill has already stung you.

Try Vylara on your repo

Review your cloud plan in Vylara, merge delivery changes as Git PRs, and deploy into your own AWS or Azure account when you’re ready.

Start free

Frequently asked questions

Is CloudFront cheaper than serving files straight from S3?
For repeat traffic, yes. CloudFront egress runs about $0.085/GB in North America and Europe versus roughly $0.09/GB for S3, and every cache hit (often 90%+ of requests for static assets) means S3 is never touched, so you stop paying S3 request and transfer fees on that traffic. For one-off or low-volume transfers, the difference is negligible.
Does a CDN make the first request to an asset faster?
No. A cache miss still pulls from the S3 origin, so the first user in each edge region pays full origin latency. The speed benefit — typically 50–200ms saved per request — only applies to cached responses, which is why a high cache hit ratio is what actually matters.
Does Vylara create the S3 bucket automatically when I merge code?
No. Merging only updates your repository with the generated configs. The S3 bucket is created in your own AWS account on your first deploy, after you review and approve the plan, and the connection details are persisted so your service and the in-app chat reference the same bucket.

Related posts