How to Deploy React App on Aws S3

How to Deploy React App on AWS S3 Deploying a React application on Amazon S3 is one of the most efficient, cost-effective, and scalable methods for hosting static web applications in the cloud. As React continues to dominate front-end development due to its component-based architecture and performance optimizations, developers increasingly seek reliable, low-maintenance hosting solutions. AWS S3 (

Oct 30, 2025 - 13:18
Oct 30, 2025 - 13:18
 0

How to Deploy React App on AWS S3

Deploying a React application on Amazon S3 is one of the most efficient, cost-effective, and scalable methods for hosting static web applications in the cloud. As React continues to dominate front-end development due to its component-based architecture and performance optimizations, developers increasingly seek reliable, low-maintenance hosting solutions. AWS S3 (Simple Storage Service) provides exactly that: a highly durable, secure, and globally accessible object storage service that can serve static files with minimal configuration.

Unlike traditional server-based hosting, S3 eliminates the need for managing virtual machines, scaling infrastructure, or handling server updates. When paired with Amazon CloudFront (a content delivery network), React apps hosted on S3 achieve lightning-fast load times across the globe. Additionally, S3 supports custom domains, HTTPS via AWS Certificate Manager, and fine-grained access controls—making it ideal for production-grade applications.

This guide walks you through every step required to deploy a React application on AWS S3—from building your app to configuring bucket policies, enabling static website hosting, and securing your site with HTTPS. Whether you’re a beginner learning cloud deployment or an experienced developer optimizing your CI/CD pipeline, this tutorial provides actionable, up-to-date instructions that ensure a smooth, production-ready deployment.

Step-by-Step Guide

Prerequisites

Before you begin deploying your React app on AWS S3, ensure you have the following:

  • A working React application (created with Create React App, Vite, or another tool)
  • An AWS account (free tier eligible)
  • A terminal or command-line interface (CLI)
  • AWS CLI installed and configured with valid credentials
  • Basic understanding of AWS services: S3, IAM, CloudFront, and Route 53 (optional)

If you don’t have an AWS account, visit aws.amazon.com and sign up. For AWS CLI setup, follow the official documentation at AWS CLI Installation Guide. Once installed, run aws configure and enter your Access Key ID, Secret Access Key, default region (e.g., us-east-1), and output format (e.g., json).

Step 1: Build Your React Application

Before uploading your React app to S3, you must generate a production-ready build. This process optimizes your code by minifying JavaScript and CSS, removing development-only code, and generating static files that can be served directly by S3.

Open your terminal, navigate to your React project directory, and run:

npm run build

or, if you’re using Yarn:

yarn build

This command creates a new folder named build in your project root. Inside this folder, you’ll find:

  • index.html – the main entry point
  • static/ – contains minified JavaScript and CSS bundles
  • asset-manifest.json – maps file names to hashed versions for caching

These files are entirely static and ready for hosting on S3. Do not modify them manually—they are generated by the React build system for optimal performance.

Step 2: Create an S3 Bucket

Next, you’ll create an S3 bucket to store your React app’s files. A bucket is a container for your objects (files). Each bucket name must be globally unique across all AWS accounts.

To create a bucket:

  1. Log in to the AWS S3 Console.
  2. Click Create bucket.
  3. Enter a unique bucket name (e.g., my-react-app-2024). Avoid uppercase letters, underscores, or special characters. Use only lowercase letters, numbers, and hyphens.
  4. Select your preferred AWS Region (choose one closest to your target audience for lower latency).
  5. Uncheck Block all public access. Since you’re hosting a public website, this access must be allowed.
  6. Check the box acknowledging that you understand the bucket will be public.
  7. Click Create bucket.

Once created, select your bucket from the list and proceed to the next step.

Step 3: Enable Static Website Hosting

By default, S3 buckets are used for object storage. To serve your React app as a website, you must enable static website hosting.

Inside your bucket:

  1. Go to the Properties tab.
  2. Scroll down to Static website hosting.
  3. Click Edit.
  4. Select Enable.
  5. Set Index document to index.html. This tells S3 to serve this file when a user visits the root URL.
  6. Set Error document to index.html. This is critical for React Router applications. Without it, refreshing pages or navigating to deep links (e.g., /about or /dashboard) will return a 404 error because S3 tries to find a file named “about” or “dashboard,” which doesn’t exist. Redirecting all errors to index.html allows React Router to handle routing client-side.
  7. Click Save changes.

After saving, you’ll see a website endpoint URL displayed at the bottom of the section. It will look like:

http://your-bucket-name.s3-website-us-east-1.amazonaws.com

Copy this URL. You can paste it into your browser to test your app—but note that it’s not secure (HTTP only) and not custom. We’ll fix that later.

Step 4: Upload Your Build Files to S3

Now, upload all the contents of your build folder to the S3 bucket.

There are two methods: using the AWS Console or the AWS CLI.

Method A: Using AWS Console

  1. In your S3 bucket, click Upload.
  2. Select Add files and choose all files inside your build folder (including subfolders like static/).
  3. Click Upload.

This method works for small apps but becomes cumbersome for large applications with hundreds of files.

Method B: Using AWS CLI (Recommended)

Open your terminal and run the following command from your project root (where the build folder is located):

aws s3 sync build/ s3://your-bucket-name --delete

Replace your-bucket-name with your actual bucket name.

The sync command uploads only new or modified files, making future deployments faster. The --delete flag ensures that any files in the bucket that no longer exist in your local build folder are removed, keeping your deployment clean.

After the upload completes, your React app is now live on S3. Visit your website endpoint URL in a browser to verify it loads correctly.

Step 5: Configure Bucket Policy for Public Access

Even though you unchecked “Block all public access” during bucket creation, you may still need to explicitly allow public read access to all objects.

Go to your bucket’s Permissions tab and scroll to Bucket policy. Click Edit and paste the following policy:

{

"Version": "2012-10-17",

"Statement": [

{

"Sid": "PublicReadGetObject",

"Effect": "Allow",

"Principal": "*",

"Action": "s3:GetObject",

"Resource": "arn:aws:s3:::your-bucket-name/*"

}

]

}

Replace your-bucket-name with your actual bucket name. Click Save changes.

This policy grants any user on the internet permission to read objects in your bucket—perfect for a public website. Never use this policy for private data.

Step 6: Set Up HTTPS with CloudFront (Optional but Recommended)

While S3 supports static website hosting, it serves content over HTTP by default. Modern browsers flag HTTP sites as “not secure,” and search engines penalize them. To serve your React app over HTTPS, you must use Amazon CloudFront, AWS’s content delivery network (CDN).

CloudFront caches your content at edge locations worldwide, improves performance, and automatically provides HTTPS via SSL/TLS certificates.

Create a CloudFront Distribution

  1. In the AWS Console, navigate to CloudFront.
  2. Click Create distribution.
  3. Under Origin Settings, set:
    • Origin Domain Name: Select your S3 bucket’s website endpoint (not the REST endpoint). It should end in .s3-website-*.amazonaws.com.
    • Origin ID: Auto-filled; leave as-is.
    • Origin Path: Leave blank.
    • Origin Access Control (OAC): Select Create new OAC.
    • Leave other settings as default.
  4. Under Default Cache Behavior Settings:
    • Viewer Protocol Policy: Set to Redirect HTTP to HTTPS.
    • Cache Policy: Select CachingOptimized.
    • Origin Request Policy: Select AllViewer.
  5. Under Distribution Settings:
    • Alternate Domain Names (CNAMEs): Enter your custom domain if you have one (e.g., www.yourapp.com).
    • SSL Certificate: Select ACM Certificate and choose a certificate for your domain (we’ll create this next).
    • Default Root Object: Set to index.html.
  6. Click Create distribution.

It may take 10–20 minutes for CloudFront to deploy. You’ll see a status of “In Progress.” Once it turns “Deployed,” you’ll see a CloudFront domain like xxxxxxx.cloudfront.net.

Request an SSL Certificate with ACM

If you want to use a custom domain (e.g., www.yourapp.com), you must request an SSL certificate from AWS Certificate Manager (ACM).

  1. Navigate to ACM in the AWS Console.
  2. Click Request a certificate.
  3. Choose Request a public certificate.
  4. Enter your domain name (e.g., www.yourapp.com and yourapp.com for both www and non-www).
  5. Click Request.
  6. Choose DNS validation and click Confirm.
  7. ACM will generate CNAME records. Go to your domain registrar (e.g., Route 53, GoDaddy, Namecheap) and add these records to your DNS settings.
  8. Wait for ACM to show “Issued.” This may take a few minutes to hours.

Once issued, return to your CloudFront distribution, edit the SSL certificate setting, and select your newly issued certificate.

Step 7: Point Your Domain to CloudFront (Optional)

If you’re using a custom domain, update your DNS records to point to your CloudFront distribution.

If you’re using Amazon Route 53:

  1. Navigate to Route 53Hosted zones.
  2. Select your domain.
  3. Create a new record:
    • Name: www (for www.yourapp.com) or leave blank for root domain (yourapp.com)
    • Type: A
    • Value: Paste your CloudFront distribution domain (e.g., d12345.cloudfront.net)
    • Click Save records.

If you’re using a third-party registrar, add an A record pointing to the CloudFront domain. Avoid CNAMEs for root domains (apex domains like yourapp.com) unless your provider supports ALIAS or ANAME records.

Best Practices

Use Versioned Builds and Cache Invalidation

React apps use hashed filenames (e.g., main.1a2b3c.js) to enable aggressive browser caching. When you deploy a new version, S3 and CloudFront serve the old cached version unless explicitly invalidated. To avoid stale content:

  • Always use npm run build to generate new builds with unique hashes.
  • Use the aws s3 sync command with --delete to ensure old files are removed.
  • If using CloudFront, invalidate the cache after each deployment. Run:
aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths "/*"

Replace YOUR_DISTRIBUTION_ID with your actual CloudFront ID. This forces CloudFront to fetch fresh files from S3 on the next request.

Enable Compression

S3 supports compression, but you must configure it manually. Enable GZIP compression for HTML, CSS, and JavaScript files to reduce bandwidth and improve load times.

While S3 doesn’t compress files automatically, CloudFront does. Ensure your CloudFront distribution has the following settings:

  • Compress Objects Automatically: Set to Yes.
  • Ensure the following MIME types are included: text/html, text/css, application/javascript, application/json.

CloudFront automatically compresses these files when requested by a browser that supports gzip.

Use Environment Variables Securely

React apps often use environment variables (e.g., REACT_APP_API_URL). These are embedded into the build at compile time. Never store secrets like API keys or database credentials in client-side code.

Instead, use environment variables only for non-sensitive configuration:

  • API endpoints
  • Feature flags
  • Analytics keys

For sensitive data, use server-side APIs or AWS AppSync, Lambda, or API Gateway to proxy requests securely.

Set Up CI/CD with GitHub Actions

Manually running npm run build and aws s3 sync is error-prone and slow. Automate your deployment using GitHub Actions or AWS CodePipeline.

Here’s a sample GitHub Actions workflow (.github/workflows/deploy.yml):

name: Deploy React App to S3

on:

push:

branches: [ main ]

jobs:

deploy:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Setup Node.js

uses: actions/setup-node@v4

with:

node-version: '20'

- name: Install dependencies

run: npm ci

- name: Build React app

run: npm run build

- name: Configure AWS credentials

uses: aws-actions/configure-aws-credentials@v3

with:

aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}

aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

aws-region: us-east-1

- name: Sync build to S3

run: aws s3 sync build/ s3://your-bucket-name --delete

- name: Invalidate CloudFront cache

run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"

Store your AWS credentials and CloudFront ID as GitHub Secrets for security.

Monitor and Log Access

Enable S3 access logs to track who accesses your files and when. Go to your bucket’s PropertiesServer access logging and enable logging to another S3 bucket.

You can also use AWS CloudWatch to monitor CloudFront metrics like request count, error rates, and latency. Set up alarms for 4xx/5xx errors to detect deployment issues quickly.

Secure Your Bucket with IAM Roles

Instead of using long-term AWS access keys in CI/CD pipelines, use IAM roles with least-privilege policies. For example, create an IAM role with permissions to write only to your specific S3 bucket and attach it to your CI/CD runner (e.g., GitHub Actions runner via OIDC).

Tools and Resources

Essential AWS Tools

  • AWS CLI: Command-line interface for managing S3, CloudFront, and IAM. Download at aws.amazon.com/cli.
  • AWS Console: Web-based dashboard for visual management of services.
  • AWS Certificate Manager (ACM): Free SSL/TLS certificates for HTTPS.
  • Amazon CloudFront: CDN to accelerate global delivery and enable HTTPS.
  • Route 53: AWS’s DNS service for custom domain management.
  • AWS CloudTrail: Logs API activity for security auditing.

Third-Party Tools

  • GitHub Actions: Automate builds and deployments without managing servers.
  • Netlify / Vercel: Alternative platforms for React hosting (though this guide focuses on S3).
  • Webpack Bundle Analyzer: Visualize bundle sizes to optimize performance.
  • Lighthouse: Chrome DevTools audit tool to test performance, accessibility, and SEO.
  • React DevTools: Browser extension for debugging React components.

Documentation and References

Real Examples

Example 1: Portfolio Website

A freelance designer built a React portfolio using Create React App. The app includes a homepage, services section, contact form, and blog. All routing is handled by React Router.

They deployed the app to an S3 bucket named portfolio-john-doe and enabled static website hosting with index.html as both index and error document. They then set up CloudFront with a custom domain (www.johndoe.design) and an ACM certificate.

After configuring DNS via Route 53, the site loads securely over HTTPS with a global CDN. Page load times dropped from 2.8s to 0.9s for users in Europe and Asia. The designer now uses GitHub Actions to auto-deploy every time they push to the main branch.

Example 2: Internal Dashboard

A startup developed a React-based internal analytics dashboard for employees. The app fetches data from a private backend API hosted on AWS Lambda.

Since the app is not public, they used S3 with bucket policy restricted to specific IAM users. They enabled server-side encryption (SSE-S3) and disabled public access entirely. They also configured CloudFront with a custom domain and added an AWS WAF rule to block requests from non-corporate IP ranges.

Employees access the dashboard via dashboard.company.com using SSO credentials. No public exposure, no cost for data transfer, and full control over access.

Example 3: E-commerce Landing Page

An e-commerce brand created a marketing landing page using React and Vite. The page includes animations, video backgrounds, and a form to collect leads.

They deployed the site to S3 and used CloudFront with a custom domain and SSL. They configured CloudFront to cache the page for 24 hours and invalidated the cache after each content update.

They also enabled logging and set up CloudWatch alarms for 404 errors (to catch broken links) and high error rates (to detect DDoS attempts). The site now handles 50,000+ daily visitors with zero downtime.

FAQs

Can I deploy a React app on S3 without CloudFront?

Yes, you can. S3’s static website hosting feature allows you to serve your React app directly over HTTP. However, this is not recommended for production. Without CloudFront, you lose HTTPS support, global caching, and performance optimization. You also cannot use custom domains with HTTPS unless you proxy through another service.

Why does my React app show a 404 when I refresh a page?

This happens because React uses client-side routing (e.g., React Router). When you refresh /about, the browser requests the server for a file named “about,” but S3 only has index.html. To fix this, set the Error Document in S3 static website hosting to index.html. This redirects all 404s to the main file, allowing React Router to handle the route.

How do I update my React app after the initial deployment?

Re-run npm run build to generate a new build folder, then use aws s3 sync build/ s3://your-bucket-name --delete to upload changes. If using CloudFront, invalidate the cache with aws cloudfront create-invalidation --distribution-id YOUR_ID --paths "/*" to ensure users see the latest version.

Is hosting on S3 free?

AWS offers a free tier for S3: 5 GB of storage, 20,000 GET requests, and 2,000 PUT requests per month for 12 months. For small personal projects, this is sufficient. Beyond that, costs are minimal—typically less than $0.50/month for a low-traffic site. CloudFront usage is billed separately but remains affordable for most use cases.

Can I use a custom domain with S3 without CloudFront?

No. S3’s static website endpoint does not support HTTPS with custom domains. You must use CloudFront to enable HTTPS and map a custom domain (e.g., www.yourapp.com) to your S3 bucket.

How do I handle API calls from my React app hosted on S3?

Make API calls to a backend service (e.g., AWS API Gateway, Lambda, or a Node.js server). Ensure your backend supports CORS (Cross-Origin Resource Sharing) to allow requests from your S3-hosted domain. Never expose secrets in client-side code.

What’s the difference between S3 REST endpoint and website endpoint?

The REST endpoint (e.g., s3.amazonaws.com/your-bucket) is used for programmatic access via APIs. The website endpoint (e.g., your-bucket.s3-website-us-east-1.amazonaws.com) is used for serving static websites and supports index and error documents. Always use the website endpoint when enabling static website hosting.

Does S3 support server-side rendering (SSR)?

No. S3 is a static hosting service. It cannot run Node.js or execute server-side code. For SSR (e.g., Next.js), you need a server-based platform like AWS Amplify, Vercel, or an EC2 instance running a Node.js server.

Conclusion

Deploying a React application on AWS S3 is a powerful, scalable, and cost-efficient solution for hosting static web applications. With minimal configuration, you can serve a high-performance React app globally, secure it with HTTPS, and automate deployments using CI/CD pipelines. The combination of S3’s durability, CloudFront’s speed, and ACM’s free SSL certificates makes this stack ideal for startups, developers, and enterprises alike.

By following the steps outlined in this guide—from building your app, configuring S3 static hosting, enabling CloudFront, securing with HTTPS, to automating deployments—you’ve equipped yourself with industry-standard knowledge for modern web deployment.

Remember: always use hashed filenames for caching, redirect all errors to index.html for React Router compatibility, and automate deployments to eliminate human error. As your application grows, consider adding monitoring, logging, and WAF rules to enhance security and reliability.

With AWS S3, you’re not just hosting a website—you’re building a resilient, scalable, and production-ready digital presence that performs globally, scales effortlessly, and costs pennies per month. Start deploying today, and experience the power of cloud-native web hosting.