Deploying a Full-Stack MERN Application on AWS: A Beginner-Friendly Guide
Learn how to deploy a MERN stack application on AWS using services such as EC2, MongoDB Atlas, and S3. This guide explains the deployment flow, environment variables, security considerations, and common challenges developers face when moving a project from localhost to the cloud.
Deploying a Full-Stack MERN Application on AWS: A Beginner-Friendly Guide
Building a MERN application locally is one thing, but deploying it so that users can access it from anywhere is where cloud platforms like AWS become extremely useful.
As a developer working with React, Node.js, Express.js, and MongoDB, I wanted to understand how a project moves from
localhost to a real production environment.In this article, I’ll explain a simple deployment architecture for a MERN application using AWS.
1. Understanding the Architecture
A typical MERN application consists of:
- React.js → Frontend
- Node.js + Express.js → Backend/API
- MongoDB → Database
A simple AWS-based architecture can look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Users
|
↓
Internet
|
↓
React Frontend
|
↓
Node.js / Express
Backend
|
↓
MongoDB AtlasFor the AWS infrastructure, we can use services such as:
- Amazon EC2 – Host the Node.js backend
- Amazon S3 – Host static frontend files
- Amazon CloudFront – Deliver frontend content globally
- MongoDB Atlas – Host the database
- AWS IAM – Manage permissions and access
- Route 53 – Manage domain names, if required
2. Preparing the Backend
Before deploying, make sure the Express backend works correctly on your local machine.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const express = require("express");
const app = express();
app.use(express.json());
app.get("/", (req, res) => {
res.json({ message: "API is running" });
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});One important change is using:
1
process.env.PORTinstead of hardcoding the port.
This allows the application to use environment-specific configurations.
3. Managing Environment Variables
Never put sensitive information directly inside your source code.
For example, avoid:
1
const MONGO_URI = "mongodb+srv://username:password@cluster...";Instead, use environment variables:
1
2
3
PORT=5000
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_secretAnd access them using:
1
process.env.MONGO_URIThis becomes especially important when your application contains:
- Database credentials
- JWT secrets
- API keys
- Third-party service credentials
4. Deploying the Backend on EC2
Amazon EC2 provides virtual servers that can run our backend application.
The basic deployment flow is:
1
2
3
4
5
6
7
8
9
10
11
12
13
Create EC2 Instance
↓
Connect using SSH
↓
Install Node.js
↓
Clone GitHub Repository
↓
Install Dependencies
↓
Configure Environment Variables
↓
Start BackendAfter connecting to the instance, we can install the required dependencies and clone our project.
For example:
1
2
3
git clone <your-repository>
cd backend
npm installThen configure the environment variables and start the application.
For a production application, using a process manager such as PM2 can help keep the Node.js process running.
5. Deploying the React Frontend
The React application needs to be built before deployment.
For a Vite application:
1
npm run buildThis generates the production build.
The generated files can be hosted using Amazon S3 for static website hosting, with CloudFront used as a CDN for better content delivery.
The flow becomes:
1
2
3
4
5
6
7
8
9
10
11
React Source Code
↓
npm run build
↓
Production Build
↓
S3
↓
CloudFront
↓
UsersThis separates the frontend from the backend and allows each part to be managed independently.
6. Connecting Frontend and Backend
During local development, the frontend might communicate with:
1
http://localhost:5000After deployment, this needs to be replaced with the production API URL.
For example:
1
VITE_API_URL=https://api.example.comThen the frontend can make requests using:
1
fetch(`${import.meta.env.VITE_API_URL}/api/users`);This is one of the most common changes required when moving an application from development to production.
7. Don't Forget CORS
If the frontend and backend are hosted on different domains, CORS needs to be configured properly.
For example:
1
2
3
4
5
const cors = require("cors");
app.use(cors({
origin: "https://example.com"
}));During development, developers often use:
1
app.use(cors());But in production, allowing every origin may not be appropriate.
It's better to explicitly allow the frontend's domain.
8. Security Considerations
Deployment is not just about making the application accessible.
Security should also be considered.
Some important practices include:
Use IAM properly
Avoid using highly privileged AWS credentials unnecessarily.
Give users and applications only the permissions they actually need.
Protect environment variables
Never commit
.env files containing secrets to GitHub.Add:
1
.envto
.gitignore.Configure EC2 Security Groups
Only expose the ports that are actually required.
For example:
1
2
3
22 → SSH
80 → HTTP
443 → HTTPSAvoid opening unnecessary ports to the public internet.
Use HTTPS
For a production application, HTTPS should be used to encrypt communication between users and your application.
9. What I Learned
The biggest lesson for me was that deployment is not simply uploading code to a server.
There are several components involved:
1
2
3
4
5
6
7
8
9
10
11
Application
+
Infrastructure
+
Networking
+
Security
+
Environment Configuration
+
MonitoringUnderstanding how these pieces work together makes it much easier to troubleshoot production issues.
For example, if an API works locally but not after deployment, the problem could be related to:
- Security Groups
- Environment variables
- CORS
- DNS
- Backend process
- Database network access
- HTTPS configuration
10. Final Thoughts
AWS provides a large ecosystem of services that can initially feel overwhelming.
Instead of trying to learn every AWS service at once, I believe developers can start with a small application and gradually understand the services required to deploy and operate it.
For a MERN developer, a good starting path is:
1
2
3
4
5
6
7
8
9
10
11
EC2
↓
IAM
↓
S3
↓
CloudFront
↓
Route 53
↓
CloudWatchOnce the fundamentals are clear, it becomes much easier to explore more advanced AWS concepts such as containers, serverless architectures, load balancing, autoscaling, and CI/CD.
My goal is to continue learning AWS by deploying real projects rather than only studying the services theoretically.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article