DEV Community

Cover image for Building an Instagram Replica from Scratch
Marwan Alshaker
Marwan Alshaker

Posted on

Building an Instagram Replica from Scratch

TL;DR: App - Source.


Designing a decent, useful app is a tough task, so I decided to outsource the design task and use an existing app. I did some research and decided to go for Instagram.

I decided to document this experience, the lessons I learned, the challenges I faced. Naturally, I underestimated the size of this undertaking, and Instagram turned out to be full of UI quirks and difficulties.

Quick statistics

Commits Issues PRs PR comments
418 30 77 566

I picked Instagram for the following reasons:

  1. It’s an excellent exercise of a real product that is used by millions, yet not impossible to replicate for a single developer.
  2. It has many interesting things to learn. SVG animations, carousels, chat UI, and lots of state management and routing.
  3. It makes for a good demonstration of my skills.

Technologies I used

Boilerplate and hosting

I used Next.js and Vercel; they were absolutely outstanding for my education journey.

State management

My brother introduced me to WordPress data stores. They were superb, made my life a lot easier. Out of the box, they give you Redux without the boilerplate, redux-saga for your asynchronous needs, they also give you a tremendous set of hooks to access your data. And they make API requests super clean and nifty. The only caveat is the GPL license, I was forced to open-source the project. This project is meant to be OSS, but it might be an issue for other projects.

Styling

For styling, I lean heavily towards pure CSS, but even with my smaller projects, CSS selector collision started to become a pain. So, I opted for CSS modules, and I really like them, thanks @markdalgleish!

Icons

I used Material UI Icons library. Instagram uses many icons and some of them are not available in MUI, so I salvaged the SVGs from Instagram.

Surprisingly difficult challenges ✨

The ring around the profile picture when the user a story.

If you dig through Instagram's source, you'll see that they implement this using canvases. After doing some research, I realized learning SVG is more valuable, so I ended up using SVGs. While I didn't get the exact effect, after a lot of fighting with dash arrays and linear gradients, I got a pretty sweet result. You can check it live here.

SVGs are super powerful, but they were counter-intuitive.

Stories Interface

This one was an epic saga. It deserves a post on its own. It has two sets of challenges:

Mobile stories and virtualization

This was a really fun one. Before I explain it, let me show you:

I had to construct a box with each face representing a user's set of stories. Then, when you drag, I'd rotate said box around the Y axis proportionally to how far you drag. This comes with a ton of state management to pause/start/mute/unmute the correct story at the right time.

It became quickly apparent, the performance was terrible. So, I had to virtualize the story elements. And now, on mobile, I only render three sets of user stories at a time, the previous one, the current, and the next one. Naturally, the edge cases had to be taken care of, e.g.: first story (no previous), last story (no next).

Desktop

On desktop, the stories had to be responsive, centered, and animated. This took a mix of responsive CSS and a sprinkle of JavaScript. I fought hard to keep it pure CSS, but some parts were impossible. Note that Instagram fully relies on JS to lay out the stories UI. And their stories UI on desktop is more buggy than my version πŸ€“

The post carousel

On mobile

As an exercise, I decided to implement the carousel manually without a library, and I ended using a mix of CSS native snap-scroll on mobile (free dragging support), and translation with overflow:hidden on desktop. The snap-scroll UX turned out to be terrible on desktop (thanks Safari!), so I kept the translation transform there. It's also not perfect on mobile, but does the job.

On desktop

Routing

Instagram uses such a strange routing system; the same URL can mean two different things, if you expand the post by clicking "View all comments" in the feed, you get a floating overlay with the post inside it. If you refresh, you get the independent post page. This was quite tricky to pull off with file-system based routing. It was much easier with React-router, though before I migrated to Next.js. I'm still not happy with the shape of my CatchAll component.

Google Safe Browsing

Sadly, after months of work, Google marked the site a phishing site the moment I deployed it! I didn't share it anywhere and merely viewed it! So, I had to implement a disclaimer page and render it before the app to clear any confusion. And I had to remove any trace of the word Instagram from the entire codebase. But I like this page, the cat's eyes follows your cursor. 😸

Unique HTML IDs

I really needed the upcoming useId hook, because my SVG masks and gradients all needed unique IDs. And using random strings messed up the SSR hydration. I ended up writing hacky keys for every SVG mask. Things like mask-${post.id}. E.g here.

Dealing with Intersection Observer

This was one was more interesting than hard. Instagram marks every post that has tags with an icon in the bottom-left corner, to grab the user's attention, they only show this icon as the post enters the viewport. I had to use IO to make that happen. Here is how it looks:

Lesson to take home

Every app seems much easier when you look at it from the outside. I thought Instagram UI would be a one-month effort, but I decided to do every detail right. And to test on Desktop on Mobile on every step. I definitely need to rethink my estimations!

Thank you

PR reviews and guidance were patiently given by @alshakero. ❀️

Top comments (2)

Collapse
 
alshakero profile image
Omar Alshaker

You did a great job on this one. But don't ask me for any more reviews till 2030.

Collapse
 
alshakerm profile image
Marwan Alshaker

Much love and appreciation ❀️