Deploy to Production — Railway/Render Deployment
You've built the Biryani Order API, Swiggy clone, and auth system. Now it's time to deploy them so the world can use them. No more localhost — your app deserves a live URL!
You've built amazing Node.js projects throughout this course. But until now, they've only been running on your local machine — accessible only to you. Deployment is the process of making your application available on the public internet so anyone can use it.
Production = real users, real data, real traffic.
Key differences between development and production:
| Development (Localhost) | Production (Live) |
|---|---|
| localhost:3000 | your-app.railway.app |
| Local MongoDB | MongoDB Atlas (Cloud) |
| .env file with secrets | Environment variables in dashboard |
| nodemon auto-restart | Process manager auto-restarts |
| Manual test with curl | Real users hitting endpoints |
| Nobody sees it | Entire world can access it |
What we'll do in this chapter:
- Prepare our app for production (PORT, CORS, scripts)
- Set up MongoDB Atlas (cloud database)
- Deploy to Railway (platform as a service)
- Configure environment variables in the hosting dashboard
- Set up CI/CD — push to GitHub, auto-deploy to Railway
By the end, your Biryani Order API will be live on the internet with a real URL! 🚀
MongoDB Atlas is a fully managed cloud database service. Instead of running MongoDB on your own server (which requires maintenance, backups, and monitoring), Atlas handles everything for you — including a free tier perfect for learning and small projects.
Setup steps:
- Go to mongodb.com/atlas and create a free account
- Create a new cluster (choose the FREE M0 tier)
- Set up database access:
- Username:
admin(or whatever you choose) - Password: Generate a strong password (save it!)
- Username:
- Set up network access — add IP whitelist:
- For development: Add your current IP
- For production: Add
0.0.0.0/0(allow from anywhere — Railway's IP changes)
- Click "Connect" → "Connect your application" → Copy the connection string
Your connection string looks like:
mongodb+srv://admin:<password>@cluster0.xxxxx.mongodb.net/biryani-api?retryWrites=true&w=majority
Replace these in your .env or Railway dashboard:
<password>→ The password you created (URL-encode special chars)biryani-api→ Your database name (create it in the URI)
Important security rules:
- Never commit connection string with password to GitHub! Use environment variables.
- Atlas free tier gives you 512 MB storage — enough for thousands of biryani orders!
- Your cluster takes 1-3 minutes to provision. Be patient and grab a chai ☕
Railway is a modern Platform-as-a-Service (PaaS) that makes deploying Node.js apps incredibly simple. Push your code, Railway detects the language, installs dependencies, and runs your start script — automatically.
Why Railway over VPS?
- No server management — No SSH, no Nginx, no systemd
- Automatic Node.js detection — Railway sees your package.json and knows what to do
- Auto-deploy from GitHub — Every push deploys automatically
- Built-in logging — See console.log output in real-time dashboard
- Free tier — Enough for learning and small projects
- Custom domains — Point your own domain (e.g., api.devinhyderabad.com)
Deploy steps:
# 1. Make sure your project has these essentials:
# package.json — Railway reads these:
# "start": "node server.js" ← Railway runs this!
# "type": "module" ← ES Modules
# 2. server.js should use process.env.PORT
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log('Server running on port ' + PORT);
});
# 3. Push your code to GitHub
git init
git add .
git commit -m "Ready for deployment! 🚀"
git remote add origin https://github.com/yourusername/biryani-order-api.git
git push -u origin main
# 4. Go to railway.com → New Project → Deploy from GitHub repo
# 5. Select your repository
# 6. Railway auto-detects Node.js, runs npm install, runs npm start
# 7. Your app is LIVE! 🎉
Common issues and fixes:
| Issue | Fix |
|---|---|
| "PORT already in use" | Don't hardcode 3000. Use process.env.PORT || 3000 |
| "MongoDB connection refused" | Check Atlas IP whitelist (add 0.0.0.0/0 or all IPs) |
| "Cannot find module XYZ" | npm install XYZ. Did you commit package-lock.json? |
| "npm start failed" | Check start script in package.json. Add "start": "node server.js" |
| CORS errors | Install cors package and configure it for your frontend domain |
Railway dashboard gives you:
- Live URL:
https://biryani-api.up.railway.app - Real-time deployment logs
- Environment variable management
- Automatic HTTPS (SSL certificate)
- Custom domain support (api.yourdomain.com)
This is the most commonly overlooked step! Environment variables in production must be set through the hosting platform's dashboard — NOT through your .env file (which only works locally).
Your production environment variables:
# Set these in Railway Dashboard → Variables tab
# NEVER commit these to GitHub!
NODE_ENV=production
PORT=3000 # Railway overrides this automatically
MONGODB_URI=mongodb+srv://admin:<password>@cluster0.xxxxx.mongodb.net/biryani-api?retryWrites=true&w=majority
JWT_SECRET=your-random-jwt-secret-string-here
JWT_EXPIRES_IN=7d
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
APP_URL=https://biryani-api.up.railway.app
How to set environment variables:
- Go to Railway dashboard → Your project → Variables tab
- Add each key-value pair
- Railway automatically restarts your app with the new variables
- Your app reads them with
process.env— same as .env!
Generate secure secrets:
# Generate a secure random JWT secret in terminal
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Output: 8f3a2b1c... (64 character hex string — use this!)
Production config pattern:
// config/index.js — Works locally AND in production!
import 'dotenv/config'; // Silent fail if .env not found
const config = {
port: process.env.PORT || 3000,
env: process.env.NODE_ENV || 'development',
mongo: {
uri: process.env.MONGODB_URI || 'mongodb://localhost:27017/biryani-dev'
},
jwt: {
secret: process.env.JWT_SECRET || 'dev-secret-change-in-production',
expiresIn: process.env.JWT_EXPIRES_IN || '7d'
},
smtp: {
host: process.env.SMTP_HOST || 'smtp.ethereal.email',
port: parseInt(process.env.SMTP_PORT) || 587,
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
},
appUrl: process.env.APP_URL || 'http://localhost:3000'
};
export default config;
Key insight: The config module uses || (OR) operator for safe defaults. When running locally, it falls back to development values. In production, Railway's environment variables override everything. This same code works in both environments without changes!
CI/CD (Continuous Integration / Continuous Deployment) means that every time you push code to GitHub, your app is automatically deployed to Railway — no manual steps required!
The CI/CD pipeline:
You write code → git push → GitHub → Railway detects changes → npm install → npm start → LIVE!
(local) (trigger) (webhook) (build) (run) (deployed)
Setting up auto-deploy:
- Connect your GitHub repo to Railway (already done in deployment step)
- Railway automatically sets up a webhook — any push to main branch triggers deployment
- That's it! Next time you push, watch the magic happen in Railway dashboard
Complete deployment workflow:
# Step 1: Make changes locally
git add .
git commit -m "Add biryani search feature"
# Step 2: Push to GitHub
git push origin main
# Step 3: Go to Railway dashboard → Deployments tab
# Watch: "Deploying... Building... Deployed!"
# Step 4: Test your live URL
curl https://biryani-api.up.railway.app/api/health
# { "success": true, "message": "🍔 Biryani Order API is running!", "uptime": 123.45 }
What to include in your deployment:
// package.json — Complete production-ready setup
{
"name": "biryani-order-api",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "node --experimental-vm-modules node_modules/.bin/jest"
},
"engines": {
"node": ">=20.0.0"
}
}
Production checklist:
- ✅
"type": "module"in package.json - ✅
"start": "node server.js"script - ✅
process.env.PORTfor port binding - ✅ CORS configured for your frontend domain
- ✅ MongoDB Atlas connection string in environment variables
- ✅ All secrets (JWT_SECRET, SMTP creds) in Railway dashboard
- ✅
.gitignorewith.env,node_modules/ - ✅
package-lock.jsoncommitted (for reproducible builds)
Congratulations! Your Node.js app is now LIVE on the internet! 🎉
From localhost to production — you've learned how the entire Node.js lifecycle works. Share your URL with friends, put it on your portfolio, and build the next Swiggy! 🚀
Key Takeaways
- ✅ Production requires MongoDB Atlas (cloud DB), environment variables, and a hosting platform
- ✅ Railway detects Node.js apps automatically — just push code to GitHub and it deploys
- ✅ Use process.env.PORT || 3000 for port — never hardcode 3000 in production
- ✅ Set environment variables in Railway dashboard, NOT in .env (which is for local only)
- ✅ MongoDB Atlas free tier (M0) gives 512 MB — enough for learning and small projects
- ✅ CI/CD: git push → auto-deploy — every commit to main branch triggers deployment
- ✅ Generate secure secrets with crypto.randomBytes(32).toString("hex")
- ✅ .gitignore must include .env, node_modules/, .DS_Store — never commit secrets
- ✅ Use a config module with fallback defaults (|| operator) for DEV/PROD parity
- ✅ Congratulations — localhost se internet par! Apne URL ko share karo duniya ke saath! 🚀
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login