DEV Community

Chinwuba
Chinwuba

Posted on

Setting up socket.io

This article covers what I learned or maybe didn't really learn.

The Problem With Traditional HTTP

Most web applications use HTTP.

The flow looks like this:

Client → Request → Server
Client ← Response ← Server
Enter fullscreen mode Exit fullscreen mode

Once the server sends the response, the connection is closed.

This works perfectly for:

  • Authentication
  • CRUD operations
  • Fetching data
  • Form submissions

But what happens when the server needs to send information without being asked?

For example:

  • A new task is assigned
  • Someone comments on a task
  • A project status changes
  • A teammate updates a board

With traditional HTTP, the browser would need to keep asking:

"Anything new?"

"Anything new?"

"Anything new?"

This technique is called polling, and it's inefficient.

That's where Socket.io comes in.

What Socket.io Actually Does

Socket.io creates a persistent connection between the client and server.

Instead of repeatedly opening and closing connections, the connection stays alive.

Now communication becomes two-way:

Client ↔ Server
Enter fullscreen mode Exit fullscreen mode

The client can send data whenever it wants.

The server can also send data whenever it wants.

This is what makes real-time applications possible.


Why Express Alone Isn't Enough

One thing that confused me initially was why Socket.io couldn't simply be attached directly to my Express app.

The answer lies in how Express works.

When you write:

app.listen(5000);
Enter fullscreen mode Exit fullscreen mode

Express creates the HTTP server internally.

You don't have direct access to it.

Socket.io, however, needs access to the raw HTTP server.

So instead of:

app.listen(PORT);
Enter fullscreen mode Exit fullscreen mode

The flow becomes:

const httpServer = createServer(app);
Enter fullscreen mode Exit fullscreen mode

Then Socket.io attaches to that server:

const io = new Server(httpServer);
Enter fullscreen mode Exit fullscreen mode

Finally:

httpServer.listen(PORT);
Enter fullscreen mode Exit fullscreen mode

This architecture allows Socket.io and Express to share the same server.


Understanding Events

Socket.io is event-driven.

Everything revolves around two methods:

socket.emit()
Enter fullscreen mode Exit fullscreen mode

and

socket.on()
Enter fullscreen mode Exit fullscreen mode

Think of them as:

emit = send
on = listen
Enter fullscreen mode Exit fullscreen mode

For example:

Client:

socket.emit("join-project", projectId);
Enter fullscreen mode Exit fullscreen mode

Server:

socket.on("join-project", (projectId) => {
  // handle join
});
Enter fullscreen mode Exit fullscreen mode

The client sends.

The server listens.

Simple.


The Concept That Made Everything Click: Rooms

The feature that finally made Socket.io make sense to me was rooms.

Imagine a walkie-talkie.

People on Channel 1 hear messages sent to Channel 1.

People on Channel 2 hear messages sent to Channel 2.

Socket.io rooms work similarly.

In my project management application:

Project A = Room A
Project B = Room B
Project C = Room C
Enter fullscreen mode Exit fullscreen mode

When a user opens a project:

socket.join(projectId);
Enter fullscreen mode Exit fullscreen mode

Now they're listening to updates from that project.

When someone creates a task:

io.to(projectId).emit("task-updated");
Enter fullscreen mode Exit fullscreen mode

Only users in that project receive the event.

Everyone else remains unaffected.

This prevents unnecessary updates and scales much better.


Where Real-Time Events Should Be Triggered

One thing I initially misunderstood was where to emit events.

My first instinct was to put everything inside the Socket.io connection handler.

But that's not where the business logic happens.

The actual changes occur inside route handlers.

For example:

POST /tasks
Enter fullscreen mode Exit fullscreen mode

creates a task.

After successfully creating the task:

  1. Save task to database
  2. Get Socket.io instance
  3. Find project room
  4. Emit update

Conceptually:

Create Task

Database Success

Emit Event

Clients Update UI
Enter fullscreen mode Exit fullscreen mode

This sequence is important.

You never want to emit an event before the database operation succeeds.


Making Socket.io Available Everywhere

Another clever pattern I learned was storing the Socket.io instance on the Express app.

app.set("io", io);
Enter fullscreen mode Exit fullscreen mode

Then inside any route:

const io = req.app.get("io");
Enter fullscreen mode Exit fullscreen mode

This prevents:

  • Circular imports
  • Global variables
  • Messy architecture

Every route can access Socket.io cleanly.


Real-World Example: Task Creation

Imagine a user creates a task.

Without Socket.io:

User A creates task
↓
Database updated
↓
User B sees nothing
↓
Must refresh page
Enter fullscreen mode Exit fullscreen mode

With Socket.io:

User A creates task
↓
Database updated
↓
Server emits event
↓
User B instantly sees update
Enter fullscreen mode Exit fullscreen mode

No refresh required.

That's the power of real-time communication.

Thanks for reading.

Top comments (0)