Handling Ephemeral State: Building a User Presence System


Node.js Socket.IO WebSockets Real-Time

The green dot next to a friend’s name. The gray dot when they go offline. Simple to look at but how does the server actually track this?

This is called User Presence, and how you store it makes a big difference in performance.


The Wrong Way: Writing to a Database

A common first instinct is to save online/offline status in your main database (like MongoDB or PostgreSQL).

The problem? Online status is ephemeral i.e. it changes constantly. Every time a user opens a tab, closes a tab, or loses WiFi for two seconds, your backend has to fire a database write just to flip a true/false value.

Databases are built for permanent data like passwords, messages, user profiles. Making them handle something this fast and temporary is the wrong tool for the job.


The Right Way: Store It in Server Memory

For a single Node.js server, the best place to store rapidly changing presence data is server memory using a JavaScript Map.

Reading and writing to a Map in memory is near-instant. No disk access, no query overhead.

One thing to know: In-memory state is cleared if the server restarts. For most presence systems, this is fine users simply reconnect and their status updates automatically.


The Code (Using Socket.IO)

// A simple map: User ID → Socket ID
const onlineUsers = new Map();

io.on("connection", (socket) => {
  const userId = socket.handshake.query.userId;

  // 1. Add user to memory when they connect
  onlineUsers.set(userId, socket.id);

  // 2. Notify everyone else they're online
  socket.broadcast.emit("status-change", { userId, isOnline: true });

  socket.on("disconnect", () => {
    // 3. Remove them from memory when they leave
    onlineUsers.delete(userId);

    // 4. Notify everyone else they went offline
    socket.broadcast.emit("status-change", { userId, isOnline: false });
  });
});

The Rule of Thumb

Data TypeWhere to Store It
Passwords, messages, profilesDatabase
Who is online right nowServer memory (Map)

Keep permanent data in your database. Keep fast, temporary data in memory. This simple separation keeps your app responsive and your database free for the work it was actually built for.

© 2026 Sijal Manandhar