Chapter 5.5☕ 22 min read

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!

01Production Preparation — Apne App Ko Duniya Ke Liye Tayar Karna

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:3000your-app.railway.app
Local MongoDBMongoDB Atlas (Cloud)
.env file with secretsEnvironment variables in dashboard
nodemon auto-restartProcess manager auto-restarts
Manual test with curlReal users hitting endpoints
Nobody sees itEntire world can access it

What we'll do in this chapter:

  1. Prepare our app for production (PORT, CORS, scripts)
  2. Set up MongoDB Atlas (cloud database)
  3. Deploy to Railway (platform as a service)
  4. Configure environment variables in the hosting dashboard
  5. 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! 🚀

02MongoDB Atlas — Cloud Database Setup

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:

  1. Go to mongodb.com/atlas and create a free account
  2. Create a new cluster (choose the FREE M0 tier)
  3. Set up database access:
    • Username: admin (or whatever you choose)
    • Password: Generate a strong password (save it!)
  4. 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)
  5. 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 ☕
03Deploy to Railway — Three-Step Deployment

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:

IssueFix
"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 errorsInstall 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)
04Environment Variables in Production — Hosting Dashboard

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:

  1. Go to Railway dashboard → Your project → Variables tab
  2. Add each key-value pair
  3. Railway automatically restarts your app with the new variables
  4. 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!

05CI/CD Pipeline — Push to GitHub, Auto Deploy

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:

  1. Connect your GitHub repo to Railway (already done in deployment step)
  2. Railway automatically sets up a webhook — any push to main branch triggers deployment
  3. 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.PORT for port binding
  • ✅ CORS configured for your frontend domain
  • ✅ MongoDB Atlas connection string in environment variables
  • ✅ All secrets (JWT_SECRET, SMTP creds) in Railway dashboard
  • .gitignore with .env, node_modules/
  • package-lock.json committed (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! 🚀
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase