DEV Community

Cover image for Building a Pure-Go Socket.IO v4 Server in Go
Md Sadmanur Islam Shishir
Md Sadmanur Islam Shishir

Posted on

Building a Pure-Go Socket.IO v4 Server in Go

Building a Pure-Go Socket.IO v4 Server in Go

What if you could build a Socket.IO-compatible server in Go without depending on an existing WebSocket or Socket.IO library?

That question led me to build gsocketio.

🔗 Live demo: https://gsocketio.vercel.app/
🔗 GitHub: https://github.com/shishir1290/gsocketio

What is gsocketio?

gsocketio is a pure-Go Socket.IO v4 server implementation.

The goal is simple:

Implement the Socket.IO and Engine.IO protocol directly in Go using the standard library.

The project intentionally avoids third-party Go networking packages such as Gorilla WebSocket and other WebSocket/Socket.IO implementations.

The result is a lightweight implementation where the protocol, transport layer, packet handling, rooms, and WebSocket framing are all part of the project.

Why build another Socket.IO server?

Go already has excellent networking capabilities, but building a Socket.IO-compatible server is an interesting engineering challenge.

Socket.IO is more than just WebSocket.

A compatible implementation needs to deal with things such as:

  • Engine.IO handshakes
  • Socket.IO packets
  • WebSocket framing
  • HTTP long polling
  • Polling → WebSocket upgrades
  • Namespaces
  • Rooms
  • Broadcasting
  • ACK packets
  • Binary events
  • Authentication payloads
  • Connection lifecycle
  • CORS
  • Concurrent connections

Building these pieces from the protocol level helped me understand how Socket.IO actually works underneath the client API.

Current protocol support

gsocketio currently targets:

  • Socket.IO v5 protocol
  • Socket.IO v4 clients
  • Engine.IO v4
  • WebSocket transport
  • HTTP long polling
  • Polling → WebSocket upgrade
  • Namespaces
  • Rooms
  • Broadcasting
  • ACKs
  • Binary events
  • Binary ACKs
  • Connection context
  • CORS / preflight
  • Concurrent server operation

The repository also contains integration tests using a real Socket.IO v4 client.

Zero third-party Go dependencies

One of the design goals was keeping the core implementation dependency-free.

The go.mod intentionally contains only the module declaration and Go version.

module github.com/shishir1290/gsocketio

go 1.22.2
Enter fullscreen mode Exit fullscreen mode

That means the transport and protocol implementation are handled inside the project itself.

Starting a server

The basic server can be created with:

srv := sio.New(nil)

srv.OnConnect("/", func(c sio.Conn) error {
    c.Join("lobby")
    return c.Emit("welcome", "Hello from Go!")
})
Enter fullscreen mode Exit fullscreen mode

Then expose the Socket.IO endpoint through net/http:

http.Handle("/socket.io/", srv)

log.Fatal(http.ListenAndServe(":8080", nil))
Enter fullscreen mode Exit fullscreen mode

That's enough to start experimenting with a Socket.IO-compatible Go server.

Connecting from a Socket.IO client

A standard Socket.IO v4 client can connect to the server:

import { io } from "socket.io-client";

const socket = io("http://localhost:8080");

socket.on("connect", () => {
    console.log("connected:", socket.id);
});

socket.on("welcome", message => {
    console.log(message);
});

socket.emit("chat", "Hello!");
Enter fullscreen mode Exit fullscreen mode

You can also explicitly test the different Engine.IO transports:

io("http://localhost:8080", {
    transports: ["websocket"]
});
Enter fullscreen mode Exit fullscreen mode

or:

io("http://localhost:8080", {
    transports: ["polling"]
});
Enter fullscreen mode Exit fullscreen mode

or allow the normal polling → WebSocket upgrade:

io("http://localhost:8080", {
    transports: ["polling", "websocket"]
});
Enter fullscreen mode Exit fullscreen mode

Rooms and broadcasting

Rooms are another important part of Socket.IO.

For example:

c.Join("lobby")
Enter fullscreen mode Exit fullscreen mode

Then broadcast an event to everyone in the room:

srv.ToRoom(
    "/",
    "lobby",
    "chat",
    c,
    "Hello everyone!",
)
Enter fullscreen mode Exit fullscreen mode

You can also broadcast to the entire namespace:

srv.ToNamespace(
    "/",
    "announcement",
    "Server maintenance soon",
)
Enter fullscreen mode Exit fullscreen mode

This makes the implementation useful for applications such as:

  • Chat applications
  • Real-time dashboards
  • Multiplayer experiments
  • Notifications
  • Collaboration tools
  • Live monitoring systems

Namespaces

gsocketio also supports Socket.IO namespaces.

For example:

srv.OnConnect("/", func(c sio.Conn) error {
    return nil
})

srv.OnConnect("/admin", func(c sio.Conn) error {
    return nil
})
Enter fullscreen mode Exit fullscreen mode

Events can then be registered for a specific namespace:

srv.OnEvent("/admin", "status", func(
    c sio.Conn,
    args []json.RawMessage,
) {
    _ = c.Emit("status", "ok")
})
Enter fullscreen mode Exit fullscreen mode

Authentication context

Socket.IO authentication data can be accessed from the connection context.

For example:

srv.OnConnect("/", func(c sio.Conn) error {
    auth := c.Context()

    log.Printf("auth: %#v", auth)

    return nil
})
Enter fullscreen mode Exit fullscreen mode

Application-specific data can also be attached to a connection:

c.SetContext(map[string]string{
    "user": "123",
})
Enter fullscreen mode Exit fullscreen mode

This gives applications a place to associate authenticated users or other connection-specific information with a Socket.IO connection.

Binary events

The implementation also supports Socket.IO binary events.

For example:

srv.OnBinaryEvent("/", "upload", func(
    c sio.Conn,
    args []interface{},
    id *int,
) {
    _ = c.Emit("upload-complete", "ok")
})
Enter fullscreen mode Exit fullscreen mode

Binary Socket.IO packets use the attachment/placeholder mechanism defined by the Socket.IO protocol.

Testing the implementation

I wanted the project to be more than just an implementation that "looks like" Socket.IO.

The repository includes tests covering different parts of the protocol and server.

Some of the validation includes:

go test ./...
Enter fullscreen mode Exit fullscreen mode

Static analysis:

go vet ./...
Enter fullscreen mode Exit fullscreen mode

Race detection:

go test -race ./...
Enter fullscreen mode Exit fullscreen mode

Formatting:

test -z "$(gofmt -l .)"
Enter fullscreen mode Exit fullscreen mode

The CI setup also tests the implementation against a real Socket.IO v4 client and checks:

  • WebSocket transport
  • Polling transport
  • Polling → WebSocket upgrade
  • Authentication payloads
  • Events
  • Next.js integration

What I learned

The most interesting part of this project wasn't writing an API like:

socket.emit("message", data);
Enter fullscreen mode Exit fullscreen mode

The interesting part was understanding what happens underneath it.

There are multiple protocol layers involved:

Socket.IO
    ↓
Engine.IO
    ↓
HTTP Polling / WebSocket
    ↓
TCP
Enter fullscreen mode Exit fullscreen mode

A Socket.IO server therefore needs to correctly handle both the Socket.IO protocol and the Engine.IO transport layer.

Implementing these pieces directly made the protocol much easier to understand.

Project structure

The repository is organized around the protocol components:

gsocketio/
├── gsocketio.go
├── go.mod
├── transport/
│   ├── transport.go
│   └── transport_test.go
├── packet/
│   ├── packet.go
│   └── packet_test.go
├── rooms/
│   ├── rooms.go
│   └── rooms_test.go
├── server/
│   └── server.go
├── logger/
│   └── logger.go
├── examples/
│   ├── basic/
│   └── chat/
└── tests/
    ├── protocol_v4_test.go
    └── server_integration_test.go
Enter fullscreen mode Exit fullscreen mode

Try it yourself

Install it with:

go get github.com/shishir1290/gsocketio@latest
Enter fullscreen mode Exit fullscreen mode

Then:

import sio "github.com/shishir1290/gsocketio"
Enter fullscreen mode Exit fullscreen mode

The project is open source, so you can inspect the implementation, run the tests, experiment with the protocol, and build your own real-time Go applications on top of it.

Final thoughts

gsocketio started as an experiment to understand how Socket.IO works at a lower level.

It has grown into a working pure-Go implementation supporting many of the features needed by real Socket.IO clients.

There is still plenty of room for improvement, optimization, compatibility testing, and additional protocol edge cases.

If you're interested in Go, WebSockets, Socket.IO, Engine.IO, networking protocols, or real-time systems, I'd love for you to check it out.

⭐ GitHub: https://github.com/shishir1290/gsocketio

🌐 Live demo: https://gsocketio.vercel.app/

If you find a protocol incompatibility or have an interesting test case, feel free to open an issue or contribute to the project.

golang #go #websocket #socketio #opensource #realtime #backend #networking

Top comments (0)