Every developer eventually reaches the same wall. The app runs perfectly on localhost, npm start works, the API responds instantly, and then someone asks the one question that changes everything. Where can this actually be seen live? AWS remains the obvious first stop for that jump. According to Second Talent's 2026 cloud infrastructure report at secondtalent.com, AWS still holds roughly 28 to 29 percent of the global cloud infrastructure market. A separate analysis of 850,000 tech job postings by Oxylabs, reported at wbiw.com, found AWS mentioned in 30 percent of listings, more than any other single technology tracked in the study.
That combination, market share and hiring demand, is exactly why so many developers want to deploy React Node.js apps on AWS as their first real production project. Most tutorials either oversimplify it into a demo that breaks under real traffic, or bury beginners under VPC subnets, RDS clusters and phpMyAdmin setups meant for a different kind of project. This guide skips both extremes and walks through exactly how to deploy React Node.js apps on AWS using a single EC2 instance, PM2, and Nginx, the setup that actually holds up once real users show up.
Why Does Deploying React and Node.js Apps Still Confuse So Many Developers?
Local development hides a lot of complexity. A single terminal command starts both the frontend and backend, both talk to each other over localhost, and nothing about ports, domains or process managers ever comes up.
Production removes all of that comfort at once. Suddenly there is a real server, a real IP address, a process that needs to survive a crash or reboot, and two separate applications that both need to run in a way real users can actually reach. Most confusion comes from developers trying to solve all of this at once instead of taking it one layer at a time, which is exactly how this guide is structured below.
There is also a second layer of confusion that trips people up even after the app is technically live. React and Node end up talking to each other differently in production than they did on localhost, since they are no longer sitting on two separate dev ports with hot reload smoothing everything over. Getting the routing between them right, so one server on one port serves both cleanly, is usually the actual moment things click for most developers going through this for the first time.
What Do You Need Before You Start?
Before touching AWS, a few things need to be ready. A working React app and Node.js backend tested locally, an AWS account with billing set up, and basic comfort with a terminal and SSH. Nothing beyond that is required.
AWS's free tier easily covers a small EC2 instance for learning and light production traffic, so cost should not be a blocker for a first deployment. Everything in this guide fits comfortably inside that free tier for the first year.
How Do You Deploy React and Node.js on AWS Step by Step?
Once the basics are ready, the actual deployment breaks down into a handful of clear steps. Each one builds on the last, starting with the server itself and ending with a live, secure domain. Following them in order avoids most of the confusion covered above.
Step 1: Set Up Your AWS EC2 Instance
Log into the AWS console and open the EC2 dashboard. Launch a new instance and select Ubuntu as the operating system, since it is the most widely documented option and pairs well with Node.js tooling. A t2.micro or t3.micro instance is enough for a small app and stays inside the AWS free tier.
During launch, AWS asks for a key pair. Create a new one and download the .pem file somewhere safe, since this file is the only way to SSH into the server later. For the security group, open port 22 for SSH, port 80 for regular web traffic, and port 443 for HTTPS. There is no need to touch VPC settings or subnets for a project this size. The default VPC AWS creates for every account works fine here.
Once the instance is running, copy its public IP address and connect to it from a terminal. Picking a region close to the app's expected users also shaves real milliseconds off every request without changing a line of code.
chmod 400 your-key.pem
ssh -i "your-key.pem" ubuntu@your-ec2-public-ip
Step 2: Install Node.js and Move Your Project to the Server
Once connected, update the server and install Node.js using NodeSource, which keeps the version current without extra tooling.
sudo apt update && sudo apt upgrade -y
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs git
With Node and git installed, clone the project directly onto the server.
git clone https://github.com/your-username/your-repo.git
cd your-repo
Keep the React frontend and Node backend inside the same repository if possible. It makes deployment and future updates far simpler than managing two servers with two separate deploy processes.
Step 3: Build the React App for Production
Move into the React project folder, install dependencies, and create a production build.
cd client
npm install
npm run build
This creates a build folder full of static HTML, CSS and JavaScript files. That folder is what actually gets served to users, not the raw React source code, so there is no development server running in production at all.
Step 4: Run Your Node.js Backend With PM2
The Node backend needs a process manager, since a script left running in a terminal window dies the moment that terminal closes. PM2 solves this by keeping the app alive, restarting it automatically if it crashes, and surviving server reboots.
sudo npm install -g pm2
cd ../server
npm install
pm2 start server.js --name api
pm2 startup
pm2 save
From this point, the Node API keeps running in the background even after closing the SSH session. It is worth checking on it occasionally too, since PM2 keeps its own logs and status view without needing anything extra installed.
pm2 status
pm2 logs api
Running these two commands after any deployment is usually enough to confirm the API restarted cleanly and is not silently crash-looping in the background.
Step 5: Handle Environment Variables Safely
Hardcoding API keys or database URLs directly into the code works locally but becomes a real problem the moment that code sits in a public GitHub repository. On the server, environment variables should live in a .env file inside the Node project folder, loaded through a package like dotenv, and that file should never get committed to git in the first place.
The React side needs its own small adjustment too. Since React builds are static files, any environment variable it needs, like the API base URL, has to be set before running npm run build, not after. Once built, that value is baked into the static files permanently, so double check it before building for production rather than after deploying and wondering why the frontend is calling the wrong endpoint.
Step 6: Configure Nginx to Serve Both React and Node
Nginx sits in front of both applications and decides where each request should go. Install it first.
sudo apt install -y nginx
Then edit the default site configuration to serve the React build folder for normal page requests, and forward anything starting with /api to the Node server running on its own port.
```server {
listen 80;
server_name your-domain.com;
root /home/ubuntu/your-repo/client/build;
index index.html;
location / {
try_files $uri /index.html;
}
location /api {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Save the file, test the configuration, and restart Nginx.
sudo nginx -t`
sudo systemctl restart nginx
Visiting the EC2 public IP in a browser at this point should load the React app, and any request to /api should reach the Node backend transparently.
Step 7: Point a Domain and Secure It With HTTPS
A raw IP address works fine for testing, but a real domain makes the deployment feel finished. Buy a domain from any registrar and create an A record pointing to the EC2 instance's public IP. Setting up an Elastic IP is worth doing too, since a regular EC2 public IP changes if the instance ever restarts, while an Elastic IP stays fixed.
Once the domain resolves correctly, Certbot handles HTTPS in a couple of commands, and Let's Encrypt issues the certificate for free.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
Certbot updates the Nginx configuration automatically and sets up renewal, so the certificate does not need manual attention again. It is worth running a quick renewal test once, just to confirm the automatic process actually works before forgetting about it entirely.
sudo certbot renew --dry-run
Should You Use EC2 or Switch to S3 and Elastic Beanstalk Instead?
This question comes up in almost every AWS deployment discussion, so it is worth answering directly. EC2 with PM2 and Nginx, the setup covered above, gives full control over the server and is the better choice for learning how deployment actually works under the hood.
S3 combined with Elastic Beanstalk or Amplify trades some of that control for convenience. S3 can host the React build as a static site cheaply and reliably, while Elastic Beanstalk manages the Node backend, handling scaling and health checks automatically. That combination suits teams that want to skip server management entirely once they already understand what is happening underneath.
Neither option is wrong. Starting with EC2 first, the way this guide walks through it, builds a clearer mental model of what a managed service like Beanstalk is actually doing behind the scenes. That understanding makes switching to a managed option later a genuine choice rather than a black box.
Conclusion
That covers the full path to deploy React Node.js app on AWS without drowning in infrastructure a small project never needed. EC2 handles the server, PM2 keeps the Node process alive, Nginx routes traffic to the right place, and Certbot handles HTTPS.
None of these pieces are complicated on their own. What makes AWS deployment feel hard is usually tutorials trying to teach RDS, load balancers and auto scaling all at once, before a developer has even shipped their first working server. Getting comfortable with this simpler setup first is what actually builds real cloud and deployment skills, the kind that transfer directly to bigger AWS projects later, including load balancers, containers and CI or CD pipelines. Once this feels natural, scaling it up is a much smaller jump than starting from zero.
Top comments (0)