PeekPost

πŸ“Έ InstaClone β€” Instagram-Inspired Full-Stack Web App

A feature-complete Instagram clone built with the MERN Stack (MongoDB, Express.js, React.js, Node.js), supporting all core Instagram features plus an InstaClone Premium subscription to enjoy an ad-free experience.


πŸ—‚οΈ Table of Contents

  1. Overview
  2. Tech Stack
  3. Features
  4. InstaClone Premium
  5. Project Structure
  6. Environment Variables
  7. Getting Started
  8. API Reference
  9. Database Schema
  10. Authentication & Security
  11. Media Handling
  12. Real-Time Features
  13. Ad System
  14. Deployment
  15. Contributing
  16. License

Overview

InstaClone is a production-grade social media platform replicating the core Instagram experience β€” from photo/video sharing and stories to real-time messaging and explore feeds. Users who want a clean, distraction-free experience can subscribe to InstaClone Premium to remove all ads from their feed, stories, reels, and explore sections.

Key Highlights


Tech Stack

Frontend

| Technology | Purpose | |β€”|β€”| | React.js 18 | UI framework | | Redux Toolkit | Global state management | | React Router v6 | Client-side routing | | Tailwind CSS | Utility-first styling | | Socket.IO Client | Real-time communication | | Axios | HTTP client | | React Query | Server state & caching | | Framer Motion | Animations | | HLS.js | Video streaming (Reels) |

Backend

| Technology | Purpose | |β€”|β€”| | Node.js | Runtime environment | | Express.js | REST API framework | | MongoDB + Mongoose | Database & ODM | | Socket.IO | WebSocket server | | JWT | Authentication tokens | | Bcrypt.js | Password hashing | | Multer | File upload middleware | | Cloudinary | Media storage & CDN | | Redis | Session caching & pub/sub | | Bull | Background job queue (notifications, emails) |

Third-Party Services

| Service | Purpose | |β€”|β€”| | Cloudinary | Image & video hosting | | Razorpay / Stripe | Premium subscription payments | | Nodemailer + SendGrid | Email verification, OTP | | Firebase (optional) | Push notifications | | Google OAuth 2.0 | Social login |


Features

πŸ‘€ Authentication & Account

🏠 Feed

πŸ“· Posts

πŸ’¬ Comments

πŸ“– Stories

🎬 Reels

πŸ” Explore

πŸ‘₯ Social Graph

πŸ‘€ Profile

πŸ’Œ Direct Messages (DMs)

πŸ”” Notifications

πŸ” Privacy & Safety

βš™οΈ Settings


InstaClone Premium

Users can subscribe to InstaClone Premium to get a completely ad-free experience across the entire platform.

What Premium Removes

| Surface | Free Tier | Premium | |β€”|β€”|β€”| | Feed sponsored posts | Every 5th post | None | | Story ads | Every 3–4 stories | None | | Reel ads | Between scrolls | None | | Explore ads | In grid | None |

Premium Pricing (example)

| Plan | Price | Billing | |β€”|β€”|β€”| | Monthly | β‚Ή89 / $1.99 | Monthly auto-renewal | | Yearly | β‚Ή699 / $14.99 | Billed annually (save ~35%) |

How It Works

  1. User navigates to Settings β†’ InstaClone Premium
  2. Selects a plan (Monthly / Yearly)
  3. Completes payment via Razorpay (India) or Stripe (International)
  4. On successful payment webhook, isPremium: true and premiumExpiry: Date are set on the User document
  5. A premiumBadge field toggles the gold checkmark on their profile (optional cosmetic)
  6. Backend middleware checks isPremium on every feed / story / reel / explore request and strips ad-injection logic for premium users
  7. A Bull job runs daily to check and expire premium subscriptions past their premiumExpiry date
  8. Users can cancel anytime β€” premium remains active until the current period ends

Premium Implementation Flow

User Clicks Subscribe
        β”‚
        β–Ό
POST /api/premium/create-order
(Razorpay order or Stripe PaymentIntent created)
        β”‚
        β–Ό
Client renders payment modal
(Razorpay Checkout SDK / Stripe Elements)
        β”‚
        β–Ό
User completes payment
        β”‚
        β–Ό
Webhook received at POST /api/premium/webhook
(Razorpay signature verified / Stripe event verified)
        β”‚
        β–Ό
User.isPremium = true
User.premiumExpiry = now + plan duration
User.premiumPlan = "monthly" | "yearly"
        β”‚
        β–Ό
All feed APIs check req.user.isPremium
β†’ true  β†’ skip ad injection
β†’ false β†’ inject ad every N posts/stories/reels

Project Structure

instaclone/
β”œβ”€β”€ client/                          # React frontend
β”‚   β”œβ”€β”€ public/
β”‚   β”‚   └── index.html
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ assets/                  # Images, icons, fonts
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ common/              # Button, Modal, Avatar, Loader, etc.
β”‚   β”‚   β”‚   β”œβ”€β”€ feed/                # FeedPost, FeedAd, FeedSkeleton
β”‚   β”‚   β”‚   β”œβ”€β”€ story/               # StoryRing, StoryViewer, StoryCreator
β”‚   β”‚   β”‚   β”œβ”€β”€ reels/               # ReelCard, ReelPlayer, ReelUpload
β”‚   β”‚   β”‚   β”œβ”€β”€ explore/             # ExploreGrid, ExploreSearch
β”‚   β”‚   β”‚   β”œβ”€β”€ profile/             # ProfileHeader, PostGrid, Highlights
β”‚   β”‚   β”‚   β”œβ”€β”€ messages/            # ChatList, ChatWindow, MessageBubble
β”‚   β”‚   β”‚   β”œβ”€β”€ notifications/       # NotificationItem, NotificationPanel
β”‚   β”‚   β”‚   └── premium/             # PremiumModal, PlanCard, PremiumBadge
β”‚   β”‚   β”œβ”€β”€ pages/
β”‚   β”‚   β”‚   β”œβ”€β”€ Home.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Explore.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Reels.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Profile.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Messages.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Notifications.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Login.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Register.jsx
β”‚   β”‚   β”‚   β”œβ”€β”€ Settings.jsx
β”‚   β”‚   β”‚   └── Premium.jsx
β”‚   β”‚   β”œβ”€β”€ redux/
β”‚   β”‚   β”‚   β”œβ”€β”€ store.js
β”‚   β”‚   β”‚   └── slices/
β”‚   β”‚   β”‚       β”œβ”€β”€ authSlice.js
β”‚   β”‚   β”‚       β”œβ”€β”€ feedSlice.js
β”‚   β”‚   β”‚       β”œβ”€β”€ storySlice.js
β”‚   β”‚   β”‚       β”œβ”€β”€ reelsSlice.js
β”‚   β”‚   β”‚       β”œβ”€β”€ messageSlice.js
β”‚   β”‚   β”‚       β”œβ”€β”€ notificationSlice.js
β”‚   β”‚   β”‚       └── premiumSlice.js
β”‚   β”‚   β”œβ”€β”€ hooks/                   # useInfiniteScroll, useSocket, useMediaUpload
β”‚   β”‚   β”œβ”€β”€ services/                # axios instance, api calls
β”‚   β”‚   β”œβ”€β”€ utils/                   # formatTime, filterImage, truncate, etc.
β”‚   β”‚   β”œβ”€β”€ socket/                  # socket.js (Socket.IO client setup)
β”‚   β”‚   β”œβ”€β”€ App.jsx
β”‚   β”‚   └── main.jsx
β”‚   β”œβ”€β”€ .env
β”‚   β”œβ”€β”€ tailwind.config.js
β”‚   └── package.json
β”‚
β”œβ”€β”€ server/                          # Express backend
β”‚   β”œβ”€β”€ config/
β”‚   β”‚   β”œβ”€β”€ db.js                    # MongoDB connection
β”‚   β”‚   β”œβ”€β”€ cloudinary.js            # Cloudinary setup
β”‚   β”‚   β”œβ”€β”€ redis.js                 # Redis connection
β”‚   β”‚   └── razorpay.js              # Razorpay / Stripe init
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ auth.controller.js
β”‚   β”‚   β”œβ”€β”€ user.controller.js
β”‚   β”‚   β”œβ”€β”€ post.controller.js
β”‚   β”‚   β”œβ”€β”€ story.controller.js
β”‚   β”‚   β”œβ”€β”€ reel.controller.js
β”‚   β”‚   β”œβ”€β”€ comment.controller.js
β”‚   β”‚   β”œβ”€β”€ message.controller.js
β”‚   β”‚   β”œβ”€β”€ notification.controller.js
β”‚   β”‚   β”œβ”€β”€ explore.controller.js
β”‚   β”‚   β”œβ”€β”€ premium.controller.js
β”‚   β”‚   └── admin.controller.js
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ User.model.js
β”‚   β”‚   β”œβ”€β”€ Post.model.js
β”‚   β”‚   β”œβ”€β”€ Story.model.js
β”‚   β”‚   β”œβ”€β”€ Reel.model.js
β”‚   β”‚   β”œβ”€β”€ Comment.model.js
β”‚   β”‚   β”œβ”€β”€ Message.model.js
β”‚   β”‚   β”œβ”€β”€ Conversation.model.js
β”‚   β”‚   β”œβ”€β”€ Notification.model.js
β”‚   β”‚   β”œβ”€β”€ Ad.model.js
β”‚   β”‚   └── PremiumTransaction.model.js
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ auth.routes.js
β”‚   β”‚   β”œβ”€β”€ user.routes.js
β”‚   β”‚   β”œβ”€β”€ post.routes.js
β”‚   β”‚   β”œβ”€β”€ story.routes.js
β”‚   β”‚   β”œβ”€β”€ reel.routes.js
β”‚   β”‚   β”œβ”€β”€ comment.routes.js
β”‚   β”‚   β”œβ”€β”€ message.routes.js
β”‚   β”‚   β”œβ”€β”€ notification.routes.js
β”‚   β”‚   β”œβ”€β”€ explore.routes.js
β”‚   β”‚   β”œβ”€β”€ premium.routes.js
β”‚   β”‚   └── admin.routes.js
β”‚   β”œβ”€β”€ middlewares/
β”‚   β”‚   β”œβ”€β”€ auth.middleware.js       # verifyToken, optionalAuth
β”‚   β”‚   β”œβ”€β”€ premium.middleware.js    # checkPremium, injectAds
β”‚   β”‚   β”œβ”€β”€ upload.middleware.js     # multer config
β”‚   β”‚   β”œβ”€β”€ rateLimit.middleware.js  # express-rate-limit
β”‚   β”‚   └── error.middleware.js      # global error handler
β”‚   β”œβ”€β”€ socket/
β”‚   β”‚   └── socket.js               # Socket.IO event handlers
β”‚   β”œβ”€β”€ jobs/
β”‚   β”‚   β”œβ”€β”€ expireStories.job.js     # Bull job β€” delete 24h stories
β”‚   β”‚   β”œβ”€β”€ expirePremium.job.js     # Bull job β€” expire subscriptions
β”‚   β”‚   └── sendEmailDigest.job.js   # Bull job β€” daily email activity
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ generateToken.js
β”‚   β”‚   β”œβ”€β”€ sendEmail.js
β”‚   β”‚   β”œβ”€β”€ uploadToCloudinary.js
β”‚   β”‚   β”œβ”€β”€ feedAlgorithm.js
β”‚   β”‚   └── adInjector.js
β”‚   β”œβ”€β”€ .env
β”‚   β”œβ”€β”€ app.js
β”‚   β”œβ”€β”€ server.js
β”‚   └── package.json
β”‚
β”œβ”€β”€ .gitignore
β”œβ”€β”€ docker-compose.yml               # Optional: containerized dev setup
└── README.md

Environment Variables

Server (server/.env)

# App
NODE_ENV=development
PORT=5000
CLIENT_URL=http://localhost:3000

# MongoDB
MONGO_URI=mongodb+srv://<user>:<password>@cluster.mongodb.net/instaclone

# JWT
JWT_SECRET=your_jwt_secret_key
JWT_REFRESH_SECRET=your_refresh_secret_key
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d

# Cloudinary
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret

# Redis
REDIS_URL=redis://localhost:6379

# Google OAuth
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

# SendGrid / Nodemailer
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_USER=apikey
EMAIL_PASS=your_sendgrid_api_key
EMAIL_FROM=no-reply@instaclone.com

# Razorpay (India)
RAZORPAY_KEY_ID=your_razorpay_key
RAZORPAY_KEY_SECRET=your_razorpay_secret
RAZORPAY_WEBHOOK_SECRET=your_webhook_secret

# Stripe (International)
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx

# Premium Plans (price in paise for Razorpay, cents for Stripe)
PREMIUM_MONTHLY_PRICE_INR=8900
PREMIUM_YEARLY_PRICE_INR=69900
PREMIUM_MONTHLY_PRICE_USD=199
PREMIUM_YEARLY_PRICE_USD=1499

Client (client/.env)

VITE_API_BASE_URL=http://localhost:5000/api
VITE_SOCKET_URL=http://localhost:5000
VITE_RAZORPAY_KEY_ID=your_razorpay_key_id
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_xxx
VITE_GOOGLE_CLIENT_ID=your_google_client_id

Getting Started

Prerequisites

1. Clone the Repository

git clone https://github.com/yourusername/instaclone.git
cd instaclone

2. Install Dependencies

# Install server dependencies
cd server
npm install

# Install client dependencies
cd ../client
npm install

3. Set Up Environment Variables

Copy the example env files and fill in your credentials:

cp server/.env.example server/.env
cp client/.env.example client/.env

4. Seed the Database (Optional)

cd server
npm run seed

This seeds the database with:

5. Run the Application

Development mode (both client and server):

# From root directory (if concurrently is set up)
npm run dev

# Or run separately:

# Terminal 1 β€” Backend
cd server && npm run dev

# Terminal 2 β€” Frontend
cd client && npm run dev

Production build:

# Build frontend
cd client && npm run build

# Start backend (serves frontend static build)
cd server && npm start

The app will be available at:


API Reference

Auth Routes β€” /api/auth

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | POST | /register | Register new user | ❌ | | POST | /login | Login user | ❌ | | POST | /logout | Logout user | βœ… | | POST | /refresh-token | Refresh JWT | ❌ | | POST | /google | Google OAuth login | ❌ | | POST | /forgot-password | Send OTP to email | ❌ | | POST | /reset-password | Reset password with OTP | ❌ | | POST | /verify-email | Verify email with token | ❌ |

User Routes β€” /api/users

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | GET | /:username | Get user profile | βœ… | | PUT | /me | Update own profile | βœ… | | POST | /:id/follow | Follow / Unfollow user | βœ… | | GET | /:id/followers | Get followers list | βœ… | | GET | /:id/following | Get following list | βœ… | | POST | /:id/block | Block / Unblock user | βœ… | | POST | /:id/restrict | Restrict / Unrestrict user | βœ… | | GET | /suggestions | Get suggested users | βœ… | | GET | /search?q= | Search users | βœ… | | DELETE | /me | Delete account | βœ… |

Post Routes β€” /api/posts

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | POST | / | Create new post | βœ… | | GET | /feed | Get home feed (with/without ads) | βœ… | | GET | /:id | Get single post | βœ… | | PUT | /:id | Edit post caption/tags | βœ… | | DELETE | /:id | Delete post | βœ… | | POST | /:id/like | Like / Unlike post | βœ… | | POST | /:id/save | Save / Unsave post | βœ… | | GET | /:id/likes | Get post likers | βœ… | | GET | /user/:userId | Get user’s posts | βœ… |

Story Routes β€” /api/stories

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | POST | / | Upload new story | βœ… | | GET | /feed | Get stories feed | βœ… | | GET | /:userId | Get user’s active stories | βœ… | | POST | /:id/view | Mark story as viewed | βœ… | | POST | /:id/react | React to story | βœ… | | DELETE | /:id | Delete story | βœ… |

Reel Routes β€” /api/reels

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | POST | / | Upload new reel | βœ… | | GET | /feed | Get reels feed (with/without ads) | βœ… | | GET | /:id | Get single reel | βœ… | | POST | /:id/like | Like / Unlike reel | βœ… | | DELETE | /:id | Delete reel | βœ… |

Comment Routes β€” /api/comments

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | POST | /post/:postId | Add comment to post | βœ… | | GET | /post/:postId | Get comments for post | βœ… | | PUT | /:id | Edit comment | βœ… | | DELETE | /:id | Delete comment | βœ… | | POST | /:id/like | Like / Unlike comment | βœ… | | POST | /:id/reply | Reply to comment | βœ… | | POST | /:id/pin | Pin comment (author only) | βœ… |

Message Routes β€” /api/messages

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | GET | /conversations | Get all conversations | βœ… | | POST | /conversations | Create new conversation | βœ… | | GET | /conversations/:id | Get messages in conversation | βœ… | | POST | /conversations/:id | Send message | βœ… | | DELETE | /messages/:id | Delete message | βœ… |

Premium Routes β€” /api/premium

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | GET | /plans | Get available plans | ❌ | | POST | /create-order | Create payment order | βœ… | | POST | /webhook | Handle payment webhook | ❌ | | GET | /status | Get user’s premium status | βœ… | | POST | /cancel | Cancel subscription | βœ… |

Explore Routes β€” /api/explore

| Method | Endpoint | Description | Auth | |β€”|β€”|β€”|β€”| | GET | / | Get explore feed (with/without ads) | βœ… | | GET | /trending | Get trending hashtags | βœ… | | GET | /hashtag/:tag | Get posts by hashtag | βœ… | | GET | /location/:id | Get posts by location | βœ… | | GET | /search?q= | Search everything | βœ… |


Database Schema

User Model

{
  username: { type: String, unique: true, required: true },
  email:    { type: String, unique: true, required: true },
  password: { type: String },                          // null for OAuth users
  fullName: String,
  bio:      String,
  website:  String,
  avatar:   String,                                    // Cloudinary URL
  isPrivate: { type: Boolean, default: false },
  isVerified: { type: Boolean, default: false },       // email verified
  followers:  [{ type: ObjectId, ref: 'User' }],
  following:  [{ type: ObjectId, ref: 'User' }],
  blockedUsers: [{ type: ObjectId, ref: 'User' }],
  restrictedUsers: [{ type: ObjectId, ref: 'User' }],
  closeFriends: [{ type: ObjectId, ref: 'User' }],
  savedPosts: [{ type: ObjectId, ref: 'Post' }],
  followRequests: [{ type: ObjectId, ref: 'User' }],
  // Premium
  isPremium:     { type: Boolean, default: false },
  premiumPlan:   { type: String, enum: ['monthly', 'yearly'], default: null },
  premiumExpiry: Date,
  premiumBadge:  { type: Boolean, default: false },
  // Auth
  googleId:      String,
  refreshToken:  String,
  twoFASecret:   String,
  twoFAEnabled:  { type: Boolean, default: false },
  // Settings
  hidelikeCounts: { type: Boolean, default: false },
  notifications: { likes: Boolean, comments: Boolean, follows: Boolean, ... },
  createdAt: Date,
  updatedAt: Date
}

Post Model

{
  author:   { type: ObjectId, ref: 'User', required: true },
  media:    [{ url: String, type: { type: String, enum: ['image','video'] }, publicId: String }],
  caption:  String,
  hashtags: [String],
  mentions: [{ type: ObjectId, ref: 'User' }],
  tagged:   [{ user: ObjectId, x: Number, y: Number }],
  location: { name: String, lat: Number, lng: Number },
  likes:    [{ type: ObjectId, ref: 'User' }],
  comments: [{ type: ObjectId, ref: 'Comment' }],
  views:    { type: Number, default: 0 },
  commentsDisabled: { type: Boolean, default: false },
  createdAt: Date
}

Story Model

{
  author:   { type: ObjectId, ref: 'User', required: true },
  media:    { url: String, type: { type: String, enum: ['image','video'] }, publicId: String },
  text:     String,
  stickers: Array,
  music:    { title: String, artist: String, url: String },
  viewers:  [{ user: ObjectId, viewedAt: Date }],
  reactions:[{ user: ObjectId, emoji: String }],
  audience: { type: String, enum: ['public', 'closeFriends'], default: 'public' },
  expiresAt:{ type: Date, index: { expires: 0 } },    // TTL index
  createdAt: Date
}

PremiumTransaction Model

{
  user:          { type: ObjectId, ref: 'User', required: true },
  orderId:       String,                               // Razorpay / Stripe order ID
  paymentId:     String,                               // Razorpay / Stripe payment ID
  plan:          { type: String, enum: ['monthly', 'yearly'] },
  amount:        Number,
  currency:      String,
  status:        { type: String, enum: ['pending','success','failed','refunded'] },
  gateway:       { type: String, enum: ['razorpay', 'stripe'] },
  createdAt:     Date
}

Authentication & Security


Media Handling


Real-Time Features

All real-time functionality is handled via Socket.IO with Redis adapter for horizontal scaling.

Socket Events

Event Direction Description
message:new Server β†’ Client New DM received
message:seen Client β†’ Server Mark messages as seen
typing:start Client β†’ Server User started typing
typing:stop Client β†’ Server User stopped typing
notification:new Server β†’ Client Push new notification
story:new Server β†’ Client Notify followers of new story
user:online Client β†’ Server User came online
user:offline Client β†’ Server User went offline
post:liked Server β†’ Client Real-time like count update

Ad System

Ads are managed by the Admin Panel and stored in the Ad collection.

Ad Injection Logic (server-side)

// middlewares/premium.middleware.js

export const injectAds = async (req, res, next) => {
  if (req.user?.isPremium) {
    req.showAds = false;
  } else {
    req.showAds = true;
  }
  next();
};

// utils/adInjector.js

export const injectAdsInFeed = (posts, ads, frequency = 5) => {
  if (!ads.length) return posts;
  const result = [...posts];
  let adIndex = 0;
  for (let i = frequency; i < result.length; i += frequency + 1) {
    result.splice(i, 0, { ...ads[adIndex % ads.length], isAd: true });
    adIndex++;
  }
  return result;
};

Ad Model

{
  title:       String,
  imageUrl:    String,
  linkUrl:     String,
  advertiser:  String,
  targetAudience: { ageMin: Number, ageMax: Number, interests: [String] },
  placement:   { type: String, enum: ['feed', 'story', 'reel', 'explore'] },
  impressions: { type: Number, default: 0 },
  clicks:      { type: Number, default: 0 },
  isActive:    { type: Boolean, default: true },
  startDate:   Date,
  endDate:     Date
}

Deployment

Frontend β€” Vercel

cd client
npm run build
vercel deploy --prod

Set environment variables in Vercel dashboard.

Backend β€” Render / Railway / AWS EC2

# On your server
git pull origin main
cd server
npm install --production
npm start

Or use the provided Dockerfile:

docker build -t instaclone-server ./server
docker run -p 5000:5000 --env-file server/.env instaclone-server

Docker Compose (Full Stack Dev)

docker-compose up --build

This spins up MongoDB, Redis, the Node.js server, and the React client together.

Environment Checklist Before Deploy


Contributing

Contributions are welcome. Please follow this workflow:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/your-feature-name
  3. Commit your changes: git commit -m "feat: add your feature"
  4. Push to the branch: git push origin feature/your-feature-name
  5. Open a Pull Request with a clear description

Commit Convention (Conventional Commits)

feat:     New feature
fix:      Bug fix
docs:     Documentation update
style:    Formatting, no logic change
refactor: Code restructure, no feature change
test:     Adding tests
chore:    Build process, dependency updates

License

This project is licensed under the MIT License β€” see the LICENSE file for details.


Built with ❀️ using the MERN Stack. Not affiliated with Meta or Instagram.