How to Deploy a React App to S3 + CloudFront

Hosting a React SPA on AWS is two services: S3 holds the built files, CloudFront caches them globally. Here's the deploy - sync to S3, front it with CloudFront, and handle SPA routing + cache busting.

Fullstack Engineerawss3cloudfront

The architecture

Build and sync to S3

npm run build                         # produces dist/ (Vite) or build/ (CRA)
aws s3 sync dist/ s3://my-app-frontend --delete

--delete removes files in the bucket that are no longer in the build, so old hashed assets don't pile up.

Put CloudFront in front

Create a distribution with the S3 bucket as the origin. The two SPA-specific settings:

Invalidate the cache on every deploy

CloudFront caches aggressively, so a new deploy won't show until you invalidate:

aws cloudfront create-invalidation \
  --distribution-id <ID> --paths "/*"

Hashed asset filenames (Vite/CRA emit app.[hash].js) can cache forever; you mainly need to invalidate index.html.

The details that matter

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How do I deploy a React app to AWS?

Build it, aws s3 sync the output to an S3 bucket, and serve it through a CloudFront distribution (S3 as origin). CloudFront gives you a global CDN, HTTPS, and lets the bucket stay private.

Why does my React app 404 on refresh when hosted on S3/CloudFront?

Client-side routes like /dashboard have no matching file in S3. Configure CloudFront custom error responses to return /index.html with a 200 for 403/404, so the React router handles the path.

How do I make a new deploy show up on CloudFront?

Create an invalidation (aws cloudfront create-invalidation --paths '/*', or just /index.html). Hashed asset files change names each build so they don't need invalidating; the HTML entry point does.

Keep learning

Fix a React useState Stale-State BugFullstack projectFix a Blank React Dashboard (Failed Fetch)Fullstack projectFix the React Search That Won't Filter (useEffect Deps)Fullstack projectFullstack roadmapStep by step to hiredFullstack interview questionsSTAR answersAll Fullstack projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →