🐦 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!

0
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