🐦 Let's Build Twitter in Java — From Scratch!

Ever wondered how Twitter works behind the scenes?
In this blog, we'll simulate a fully functional Twitter-like system in Java—from creating users to posting tweets and generating personalized feeds. Not only that, we’ll learn how to build a feed using a heap-based algorithm with custom sort logic, just like real-world systems.
This isn’t just code—it’s a hands-on walkthrough of designing a scalable social platform in the most fun and beginner-friendly way possible!
🚀 What We’re Building
Our system will support:
✅ Creating Users
✅ Posting Tweets
✅ Following Other Users
✅ Retweeting Posts
✅ Generating Dynamic Feeds (Sorted by time or popularity)
🧱 1. Designing the Core Entities
👤 User
class User {
String id;
String name;
Set<String> followers = new HashSet<>();
Set<String> following = new HashSet<>();
List<String> tweetIds = new ArrayList<>();
List<String> retweetIds = new ArrayList<>();
public User(String id, String name) {
this.id = id;
this.name = name;
}
}
📝 Tweet
class Tweet {
String id;
String userId;
String content;
long timestamp;
Set<String> likedBy = new HashSet<>();
int retweetCount = 0;
public Tweet(String id, String userId, String content, long timestamp) {
this.id = id;
this.userId = userId;
this.content = content;
this.timestamp = timestamp;
}
}
🔁 Retweet
class Retweet {
String id;
String userId;
String originalTweetId;
long timestamp;
public Retweet(String id, String userId, String originalTweetId, long timestamp) {
this.id = id;
this.userId = userId;
this.originalTweetId = originalTweetId;
this.timestamp = timestamp;
}
}
📰 FeedItem
class FeedItem {
String type; // "TWEET" or "RETWEET"
String actorId; // who tweeted or retweeted
Tweet tweet;
long timestamp;
public FeedItem(String type, String actorId, Tweet tweet, long timestamp) {
this.type = type;
this.actorId = actorId;
this.tweet = tweet;
this.timestamp = timestamp;
}
@Override
public String toString() {
return String.format("[%s] %s: %s (at %d)", type, actorId, tweet.content, timestamp);
}
}
🛠️ 2. TwitterService
class TwitterService {
Map<String, User> users = new HashMap<>();
Map<String, Tweet> tweets = new HashMap<>();
Map<String, Retweet> retweets = new HashMap<>();
AtomicInteger userIdGen = new AtomicInteger(1);
AtomicInteger tweetIdGen = new AtomicInteger(1);
AtomicInteger retweetIdGen = new AtomicInteger(1);
public String createUser(String name) {
String id = "U" + userIdGen.getAndIncrement();
users.put(id, new User(id, name));
return id;
}
public String postTweet(String userId, String content) {
long timestamp = System.currentTimeMillis();
String id = "T" + tweetIdGen.getAndIncrement();
Tweet tweet = new Tweet(id, userId, content, timestamp);
tweets.put(id, tweet);
users.get(userId).tweetIds.add(id);
return id;
}
public String retweet(String userId, String originalTweetId) {
long timestamp = System.currentTimeMillis();
String id = "RT" + retweetIdGen.getAndIncrement();
Retweet retweet = new Retweet(id, userId, originalTweetId, timestamp);
retweets.put(id, retweet);
users.get(userId).retweetIds.add(id);
Tweet original = tweets.get(originalTweetId);
if (original != null) {
original.retweetCount++;
}
return id;
}
public void follow(String followerId, String followeeId) {
users.get(followerId).following.add(followeeId);
users.get(followeeId).followers.add(followerId);
}
public List<FeedItem> generateFeed(String userId, int k, Comparator<FeedItem> comparator) {
PriorityQueue<FeedItem> heap = new PriorityQueue<>(comparator);
User user = users.get(userId);
for (String followeeId : user.following) {
User followee = users.get(followeeId);
for (String tweetId : followee.tweetIds) {
Tweet t = tweets.get(tweetId);
heap.offer(new FeedItem("TWEET", followeeId, t, t.timestamp));
if (heap.size() > k) heap.poll();
}
for (String retweetId : followee.retweetIds) {
Retweet r = retweets.get(retweetId);
Tweet t = tweets.get(r.originalTweetId);
heap.offer(new FeedItem("RETWEET", followeeId, t, r.timestamp));
if (heap.size() > k) heap.poll();
}
}
List<FeedItem> result = new ArrayList<>(heap);
result.sort(comparator.reversed());
return result;
}
public void printFeed(String userId, int k, Comparator<FeedItem> comparator) {
System.out.println("---- Feed for " + users.get(userId).name + " ----");
List<FeedItem> feed = generateFeed(userId, k, comparator);
for (FeedItem item : feed) {
System.out.println(item);
}
}
public static Comparator<FeedItem> sortByTimestamp() {
return Comparator.comparingLong(item -> item.timestamp);
}
public static Comparator<FeedItem> sortByPopularity() {
return (a, b) -> Integer.compare(
b.tweet.likedBy.size() + b.tweet.retweetCount,
a.tweet.likedBy.size() + a.tweet.retweetCount
);
}
}
🧪 3. Simulation
public class TwitterSimulation {
public static void main(String[] args) throws InterruptedException {
TwitterService service = new TwitterService();
String alice = service.createUser("Alice");
String bob = service.createUser("Bob");
String charlie = service.createUser("Charlie");
service.follow(alice, bob);
service.follow(alice, charlie);
service.follow(bob, charlie);
String t1 = service.postTweet(bob, "Hello from Bob!");
Thread.sleep(10);
String t2 = service.postTweet(charlie, "Hey, I'm Charlie.");
Thread.sleep(10);
String t3 = service.postTweet(bob, "Another tweet from Bob.");
Thread.sleep(10);
service.retweet(charlie, t1);
Thread.sleep(10);
service.retweet(bob, t2);
service.printFeed(alice, 10, TwitterService.sortByTimestamp());
System.out.println();
service.printFeed(bob, 10, TwitterService.sortByPopularity());
}
}
🧾 Sample Output
---- Feed for Alice ----
[RETWEET] Charlie: Hello from Bob! (at 1714712661121)
[TWEET] Bob: Another tweet from Bob. (at 1714712661090)
[TWEET] Charlie: Hey, I'm Charlie. (at 1714712661073)
[TWEET] Bob: Hello from Bob! (at 1714712661059)
---- Feed for Bob ----
[RETWEET] Bob: Hey, I'm Charlie. (at 1714712661135)
[RETWEET] Charlie: Hello from Bob! (at 1714712661121)
[TWEET] Bob: Another tweet from Bob. (at 1714712661090)
[TWEET] Charlie: Hey, I'm Charlie. (at 1714712661073)
[TWEET] Bob: Hello from Bob! (at 1714712661059)
🎉 That’s a Wrap!
We just built a working simulation of Twitter in Java! Use it to level up your coding, system design skills, and maybe even impress your interviewers!
Subscribe to my newsletter
Read articles from Milton Rodrigues directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Milton Rodrigues
Milton Rodrigues
Hi, I am a Backend Developer at LSEG. I build backend systems using Java, Spring/Micronaut/SpringBoot, AWS