1.Static Output or Server Rendering
A React build produces either a folder of files or a server. If it is a folder — plain React, or Next.js exported statically — it goes in a private S3 bucket behind CloudFront and there is nothing to run. If the app renders pages per request, something has to execute that code: a container behind a load balancer, or a function at the edge. Which one you have is decided by the framework configuration, not by preference.
Key features
- Static output means no compute to patch, scale, or pay for while idle — CloudFront serves files from S3
- The S3 bucket stays private; CloudFront reaches it with origin access control (OAC), which AWS recommends over the legacy origin access identity
- Using OAC with an S3 bucket origin requires S3 Object Ownership set to Bucket owner enforced, the default for new buckets
- A bucket configured as an S3 website endpoint must be attached as a custom origin, and cannot use OAC or OAI at all
- Client-side routing needs CloudFront to answer 403 and 404 from the origin with `/index.html` and a 200, or deep links break on refresh
- Server rendering means a running process: ECS or Lambda, with cold starts, a deployment, and a scaling policy to own
What each rendering mode actually needs from AWS
- Static output — S3 + CloudFront
- The build produces files; nothing executes at request time
- CloudFront serves from edge caches, origin is rarely touched
- Scales with no configuration and costs nothing while idle
- Deploy is a sync plus an invalidation of the changed paths
- Cannot do per-request server logic, secrets, or SSR data fetching
- Server rendering — ECS or Lambda
- The build produces a server; code runs on every uncached request
- Needed for SSR data fetching, per-user pages, server actions
- Has cold starts (Lambda) or a warm fleet to pay for (ECS)
- Deploy is a rolling release with health checks and rollback
- Still put CloudFront in front, and still serve assets from S3
Signature
files → S3 (private) + CloudFront + OAC · server → ECS/Lambda behind CloudFront · SPA → 403/404 ⇒ /index.html 200
If the build produces files, ship them from a private S3 bucket behind CloudFront with OAC, and map 403/404 to /index.html with a 200 so deep links work. If it produces a server, run it on ECS or Lambda — but keep static assets on the S3 origin, and only render the routes that actually need rendering.