Coding Heaven logo

Coding Heaven

Create Instagram Clone with React and Node. Part 1

    Category: react
Author's Photo

Author: Vlada

Date: 12/9/2025

The Astro logo on a dark background with a pink glow.

Create Instagram Clone web app

Hey dev, happy holidays! Today we are going to start a new project a clone of Instagram. We are going to create a web version of the app. The app’s functionality will include listing user profiles, the ability to add posts, follow other users, and display the feed of people we are following.

This app was listed on my resume, and I was asked about it a lot during interviews, so I think it can help you improve your skills and be a great project for your portfolio.

We are going to use Node.js, Express.js, and MongoDB for our backend and database. On the front-end side, we will use React.

Since the project is big, I have split it into a few parts, so we will have around 3–5 articles.

The source code you can find here
Let’s get started!


Set Up our Node backend

We are going to start by creating a new Node.js application. Make sure you have Node.js and npm installed—if you don’t, check out this How to Install Node.js article.

After you have Node.js installed, create a new directory by running
$ mkdir instaClone in your terminal.
Then move into the newly created directory using $ cd instaClone
Inside this directory, we are going to initialize our Node.js application by running:

npm init

This command will ask you a few questions about your project, but the only required field is the project name. This will be our backend. After the project is set up, we need to install Express.js. Run the following command inside your project:


$ npm install express

Check your package.json again — Express should appear in the dependencies. If it does, then we are ready to create our first file: server.ts.
We want to place it inside the src folder, so the structure of our backend will be:
instaClone/src/server.ts

// Server.ts
import express from "express";
import cors from "cors";

const app = express();
const port = 3000;

app.use(cors()); // we use to make sure our front-end will be able to make calls to backend

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Our server imports Express and CORS, then defines the app and uses CORS as middleware. This ensures that if our backend receives requests from any origin (in our case, from our front end), it will not reject them but will process the request normally.


Create User Routes

As you may notice, we didn't define any routes in our server.ts. Since we will have many routes, I want to keep the file clean by creating a separate file to handle them. So let's create a new directory named routes, and inside it create a new file called userRoutes.ts. Inside place this code:


// src/routes/userRoutes.ts

import { Router } from "express";

const router = Router();

// Dynamic route for getting user by ID
router.get("/:id", getUserProfile); //get endpoint

export default router;

We created a router and a new GET endpoint that will execute the getUserProfile method when a user visits a specific route. Now let's update our server.ts file and register the newly created endpoint.

// Server.ts
// .. prev code
app.use(cors());

app.use("/user", userRoutes); // add this line

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Now our server.ts knows about the /user route. Next, let's create a controller that will define the getUserProfile method, which is responsible for returning data for the /user/1234 GET route.

Create Controllers and Services

Set Up Controllers

Create a new directory inside src and name it controllers. Inside that folder, create a new file called userController.ts. The code in this file will handle all user profile-related endpoints, so we will place the addUser, removeUser, and updateUserProfile API calls in the userController. Place the following code inside the file:


// src/controllers/userController.ts
import { Request, Response } from "express";

export const getUserProfile = async (req: any, res: any) => {
  const { id } = req.params;
  // imititate response from the database
  const profileData = await userService.getUserById(id);
  res.send(profileData);
};

Our getUserProfile method is asynchronous. It reads the id from the endpoint and uses it to call the getUserById service, which is supposed to query the database and return the data for the user with the requested Id.


Set Up Service

Let's create a service and add some mock data to simulate a database call. Create a new folder inside src and name it Services. Inside, create a new file called userService.ts. In this file, we will place the following code:

//src/services/userService.ts
export const getUserById = async (id: string) => {
  let response = (response = {
    id: "1234",
    username: "theCodingHeaven",
    userAcountName: "Coding Heaven",
    numberOfPosts: 100,
    numberOfFollowers: 52,
    numberOfFollowing: 1,
    profileDescription: "Learn to code with me! It's going to be fun",
    threadName: null,
    ProfileImgSrc: "https://thecodingheaven.com/logoHeaven.png",
    ListOfPosts: images,
  });

  return response;
};

Our method returns an object containing various properties needed for our user profile. Normally, this data would be fetched from a database, but for the initial setup we will use mock data.

Now, let's follow the rules of strict typing and create a type to define this object. This is a good practice, and after all, we are working with TypeScript for a reason. Update our service with the following:

//src/services/userService.ts

export type UserProfile = {
  id: string;
  username: string;
  userAcountName: string;
  numberOfPosts: number;
  numberOfFollowers: number;
  numberOfFollowing: number;
  profileDescription: string;
  threadName: string | null;
  ProfileImgSrc: string;
  ListOfPosts: Images[]; // this one is a separate object
};

// every image will have its own properties
export type Images = {
  id: string;
  imgSrc: string;
  author: string;
  type: string;
};

export const getUserById = async (id: string) => {
  // Imitate user data from the database
  let response: UserProfile;
  if (id == "1234") {
    response = {
      id: "1234",
      username: "theCodingHeaven",
      userAcountName: "Coding Heaven",
      numberOfPosts: 100,
      numberOfFollowers: 52,
      numberOfFollowing: 1,
      profileDescription: "Learn to code with me! It's going to be fun",
      threadName: null,
      ProfileImgSrc: "https://thecodingheaven.com/logoHeaven.png",
      ListOfPosts: images,
    };
  } else {
    response = {
      id: "123",
      username: "Michael S",
      userAcountName: "MikeS",
      numberOfPosts: 900,
      numberOfFollowers: 3600,
      numberOfFollowing: 1500,
      profileDescription: "Working out is my life",
      threadName: null,
      ProfileImgSrc:
        "https://cdn.pixabay.com/photo/2024/11/07/11/58/fitness-9180669_1280.jpg", //use your own image url
      ListOfPosts: imagesTemp,
    };
  }

  return response;
};

Our service now defines the UserProfile and Images types. It also returns a user with ID 1234 or 123, depending on the route id. Again, this is all mock data, which we will replace with actual data from the database later on.

Update imports and add more Mock Data

Since we created our service, let's go ahead and import it into our Controller.


// src/controllers/userController.ts
import * as userService from "../services/userService"; // add this line

export const getUserProfile = async (req: any, res: any) => {
  /*Code here stays the same*/
};

Awesome! Our first route is ready. I want to add more mock data for user images so that our Instagram gallery will have some initial posts. Let's create a temporary file inside src and name it tempData.ts. Inside, we will define:


// src/tempData.ts

import { Images } from "./services/userService";

export const images: Images[] = [
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2015/10/01/20/28/animal-967657_1280.jpg",
    id: "1",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2017/03/27/13/23/dog-2178696_1280.jpg",
    id: "2",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2016/11/21/14/47/kitten-1845789_1280.jpg",
    id: "3",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2018/09/25/21/32/monkey-3703230_640.jpg",
    id: "4",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2014/01/22/08/12/seagull-249638_640.jpg",
    id: "5",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2023/04/07/07/14/cat-7905702_640.jpg",
    id: "6",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2020/10/14/01/40/parrot-5653140_640.jpg",
    id: "7",
    author: "codingHeaven",
    type: "posts",
  },
  {
    imgSrc:
      "https://cdn.pixabay.com/photo/2015/09/23/00/30/deer-952744_640.jpg",
    id: "8",
    author: "codingHeaven",
    type: "posts",
  },
];

export const imagesTemp: Images[] = [
  {
    id: "12",
    imgSrc:
      "https://cdn.pixabay.com/photo/2024/11/07/11/58/fitness-9180669_1280.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "13",
    imgSrc:
      "https://cdn.pixabay.com/photo/2022/09/06/21/37/couple-7437534_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "14",
    imgSrc:
      "https://cdn.pixabay.com/photo/2017/04/25/20/18/woman-2260736_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "15",
    imgSrc:
      "https://cdn.pixabay.com/photo/2021/09/15/01/52/running-6625457_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "16",
    imgSrc:
      "https://cdn.pixabay.com/photo/2016/11/29/09/10/man-1868632_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "17",
    imgSrc:
      "https://cdn.pixabay.com/photo/2021/07/15/04/27/gymnast-6467431_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "18",
    imgSrc:
      "https://cdn.pixabay.com/photo/2024/02/09/13/26/ai-generated-8563109_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
  {
    id: "19",
    imgSrc:
      "https://cdn.pixabay.com/photo/2017/08/04/01/52/karate-2578819_640.jpg",
    author: "PixabayUserX",
    type: "posts",
  },
];

So both of imagesTemp and images are arrays of Images types, that we exported from our userService.ts. Again, we need this types for type safety, and for easier code writing.

Now let's import this data to our service:


//src/services/userService.ts

import { images, imagesTemp } from "../tempData";
//Code stays the same

Running the Project

Create a new directory inside src and name it controllers. Inside that folder, create a new file called userController.ts. Place the following code inside the file:


{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  }
}

We tell Node.js that we want to compile our .ts files into ES2020 JavaScript so that we can actually run our app. Now, we can start the app with:


$ npx ts-node src/server.ts

Alternatively, you can add this command to the dev script in package.json and run it using npm run dev. So, now if we go to http://localhost:3000/user/1234 we should see something like this:


{
  "id": "1234",
  "username": "theCodingHeaven",
  "userAcountName": "Coding Heaven",
  "numberOfPosts": 100,
  "numberOfFollowers": 52,
  "numberOfFollowing": 1,
  "profileDescription": "Learn to code with me! It's going to be fun",
  "threadName": null,
  "ProfileImgSrc": "https://thecodingheaven.com/logoHeaven.png",
  "ListOfPosts": [
    {
      "imgSrc": "https://cdn.pixabay.com/photo/2015/10/01/20/28/animal-967657_1280.jpg",
      "id": "1",
      "author": "codingHeaven",
      "type": "posts"
    },
    {
      "imgSrc": "https://cdn.pixabay.com/photo/2017/03/27/13/23/dog-2178696_1280.jpg",
      "id": "2",
      "author": "codingHeaven",
      "type": "posts"
    },
    {
      "imgSrc": "https://cdn.pixabay.com/photo/2016/11/21/14/47/kitten-1845789_1280.jpg",
      "id": "3",
      "author": "codingHeaven",
      "type": "posts"
    },
    {
      /*Other objects*/
    }
  ]
}

In the next article, we will create a React app, set up a user profile, and fetch user data from our backend. Before I let you go, I just want to remind you that I have a YouTube channel where I share hands-on tutorials that can help you learn even more effectively.

Thank you for reading, and Happy Coding 🚀!