Desktop Pricing Docs Blog About GitHub Get started
← Back to blog

Image hosting API vs raw S3 + CloudFront

"Just put it in S3 and stick CloudFront in front" is the reflex answer for hosting images on AWS. It works — it also means a bucket, an access policy, a CloudFront distribution, an IAM identity, and a metered egress bill once you outgrow the free allowance. Here's the honest comparison with a purpose-built hosting API, including when the DIY route is still the right one.

There's nothing wrong with S3 and CloudFront. They're the workhorses of the internet. But "store an image, serve it fast" turns into a surprising amount of setup, and — more quietly — an ongoing egress bill that scales with how often your images are viewed. If images are a core part of what you ship, that math matters.

What "just use S3" actually involves

The one-liner hides the parts list. To go from zero to a public, CDN-backed image URL you typically wire up:

  • An S3 bucket plus a public-access configuration (bucket policy, or an Origin Access Control so only CloudFront can read it).
  • A CloudFront distribution with an origin, cache behaviors, and a deploy wait of several minutes before it's live.
  • An IAM user or role with scoped permissions and access keys, so your app can upload.
  • Your own upload path and validation — content-type checks, size limits, SVG safety checks — because S3 will happily store whatever you send it.
  • Cache invalidations when you replace an image, which are themselves metered past the free monthly allotment.

Compare that with the purpose-built path: register, then upload.

# The short version — bucket, public access, CDN, IAM.
# (Omits the OAC, cache-behavior, and IAM-policy JSON.)
aws s3 mb s3://my-images
# (New buckets block all public access by default — you must
# disable that first, or use an Origin Access Control instead.)
aws s3api put-bucket-policy --bucket my-images \
  --policy file://public-read.json
aws cloudfront create-distribution \
  --origin-domain-name my-images.s3.amazonaws.com
# ...wait ~15 min for the distribution to deploy...

# Then, for every upload:
aws s3 cp chart.png s3://my-images/chart.png
# → https://d111111abcdef8.cloudfront.net/chart.png
# (+ egress metered per GB past CloudFront's free 1 TB/mo)

Side by side

S3 + CloudFront
Hosting API
Time to first URL
~15+ min (distribution deploy)
One API call
Setup
Bucket + policy/OAC + distribution + IAM
Register, get a key
Upload auth
IAM identity + access keys
Bearer API key
Egress cost
Metered past 1 TB/mo free (~$0.085/GB)
Zero egress
Image validation
Do it yourself
Built in (magic bytes, SVG safety checks)
Free tier
1 TB/mo egress + 10M reqs free, then metered
Fixed always-free allotment

The egress trap

This is the part that doesn't show up in a proof-of-concept. CloudFront includes 1 TB of data-out free every month — generous for a small site, and invisible at first. Past that, it charges roughly $0.085 per GB in North America and Europe (varying by region and volume), plus per-request fees. Then a popular page or a hotlinked asset ships thousands of GB beyond the allowance and the line item is suddenly real. Because you're billed on views, your cost scales with your success.

PixelVault stores on Cloudflare R2, which has no egress fees — you pay for storage and operations, not for people looking at your images. For view-heavy workloads that single difference often dominates the whole comparison.

When S3 + CloudFront is still the right call

Plenty of times, honestly. Reach for the DIY stack when:

  • You're already all-in on AWS and want everything under one bill and one IAM boundary.
  • You need edge compute — Lambda@Edge or CloudFront Functions for on-the-fly transforms, signed cookies, header rewrites, or WAF integration.
  • You depend on deep S3 features: storage-class lifecycle tiers, cross-region replication, event triggers, or Athena/analytics over your objects.
  • You're at a scale with committed-use or private pricing that changes the egress math in your favor.

If that's you, the control is worth the setup. Don't switch just to save a few config steps.

When a hosting API wins

For a large middle of projects, the tradeoff runs the other way:

  • You just need upload → URL, not a storage platform to administer.
  • Your images are viewed a lot, so metered egress is the silent bill you'd rather not have.
  • You're a small team or a side project and don't want to babysit buckets, policies, and distributions.
  • Agents or automation upload images on their own — a single Bearer-auth endpoint (or an MCP tool) beats provisioning IAM.
  • You'd rather have a fixed, always-free allotment than a usage-metered bill to keep an eye on.

Free to start

PixelVault's free tier includes 200 MB storage, 500 uploads/month, and 1 GB bandwidth — no credit card, no trial clock, zero egress. Enough to replace an S3 + CloudFront setup for a lot of projects before you pay anything. Paid plans start at $9/month.

Read the API docs →