Social Media App (Full Stack)
Part of the Full Stack Developer Roadmap
In short
Likes, follows, comments and a feed: everyone knows how a social app should feel, so every lag shows. It's great practice for connected data and instant-feeling updates.
Posts, a feed, comments, likes and profiles — practice for connected data, real-time-ish updates, and building an app people intuitively understand how to use.

Think of it like this
The hostel corridor pinboard
Someone pins a trip photo, friends stick little hearts on it and write notes below. You walk past and see the newest photos from people you know. That board is your feed, and the hearts are likes.
Watch it happen
Tapping like, the optimistic way
1/5The UI updates at once, before the server replies. That's an optimistic update.
The big ideas
What you need to know
Follows are a join table
A follows table with follower_id and following_id. The feed is posts by people in that list, newest first.
Likes need a unique pair
One row per (user, post) with a unique constraint, plus a stored count so the feed doesn't count every time.
Feel instant
Optimistic likes and comments make the app feel fast. Roll back cleanly if the server says no.
Uploads go direct
Upload photos straight to storage with a signed URL, then save only the URL in your database.
See it in code
Walk through the code
1"use client";2import { useOptimistic, startTransition } from "react";3import { toggleLike } from "./actions";4 5export function LikeButton({ postId, liked, count }: { postId: string; liked: boolean; count: number }) {6 const [state, flip] = useOptimistic({ liked, count }, (s) => ({7 liked: !s.liked,8 count: s.count + (s.liked ? -1 : 1),9 }));10 const onClick = () => startTransition(async () => {11 flip(null);12 await toggleLike(postId); // server action: writes to the DB, then revalidates13 });14 return <button onClick={onClick}>{state.liked ? "Liked" : "Like"} · {state.count}</button>;15}1/3The optimistic version of the state: flip liked and move the count by one.
React's useOptimistic shows the new like straight away. If the server action fails, React drops the optimistic state and the real value shows again.
Save yourself the pain
Common mistakes
Oops
Running COUNT(*) on the likes table for every post in the feed.
Do this instead
Keep a like_count column on posts, updated in the same transaction as the like row.
Oops
Loading every post from everyone and filtering the feed in React.
Do this instead
Build the feed query on the server with a JOIN on follows and cursor pagination.
Your mission
First milestone: post, follow, like
Quick check
A user double-taps like very fast and two requests reach the server. How do you stop the like counting twice?
Go deeper
- 1Implement an infinite-scrolling feed with proper pagination.
- 2Add optimistic UI for likes and comments so interactions feel instant.
- 3Build a profile page showing a user's own posts and activity.
More projects at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.