learning-labs: SSE Practice Notes and Implementation Tips
Background
In @learning-labs, I organized a focused SSE (Server-Sent Events) practice track to connect the dots between concepts, implementation, and testing, while clarifying when SSE is a better fit than WebSocket.
The materials live in learning-labs/sse/, source:
https://github.com/wfnking/learning-labs/tree/master/sse
Including:
go-example/: a complete Go SSE server + browser test pagenode-example/: Node.js CLI SSE clientsREADME.md: concepts, formats, implementation notes, and use cases
Core SSE Traits (Practice View)
- Server-to-client only: ideal for notifications, logs, and progress updates
- HTTP-based:
Content-Type: text/event-stream, no extra protocol - Auto-reconnect: EventSource handles retries with
retryandLast-Event-ID - Named events: use the
event:field to classify streams
If you only need server push and no bidirectional messaging, SSE is usually simpler and easier to operate.
Server Implementation Essentials
1) Required response headers
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
2) Standardize message formatting
func formatSSEMessage(event, data string) string {
if event != "" {
return fmt.Sprintf("event: %s\ndata: %s\n\n", event, data)
}
return fmt.Sprintf("data: %s\n\n", data)
}
3) Keep the connection open + flush
With long-lived SSE connections:
- keep the connection alive
- flush on each write
- clean up on client disconnect
4) Hub pattern for concurrency
The learning project uses a minimal hub to avoid blocking:
type SSEHub struct {
clients map[string]*SSEClient
register chan *SSEClient
unregister chan *SSEClient
broadcast chan string
}
Practice Examples (learning-labs/sse)
Go endpoints
/events: basic broadcast/clock: push time every second/stock: simulated stock updates (JSON)
Node clients
CLI scripts for validating different streams:
basic.js: baseline connection + messagesclock.js: real-time clock feedstock.js: JSON parsing and display
SSE vs WebSocket: My Rule of Thumb
- Server push only → choose SSE
- Bidirectional or binary → choose WebSocket
SSE wins on simplicity and native browser support for lightweight real-time feeds.
Common Pitfalls (from practice)
- Proxy buffering: intermediaries may buffer responses and delay events
- Browser connection limits: ~6 SSE connections per host on HTTP/1.1
- Missing flush: no immediate delivery without
Flush() - Leaked clients: forget to remove disconnected clients → memory leaks
Quick Start
cd learning-labs/sse/go-example
go run main.go
Open: http://localhost:8888
Or test with Node clients:
cd learning-labs/sse/node-example
npm install
npm run basic
Closing
This SSE practice in @learning-labs is meant to be a minimal, runnable knowledge sample:
it preserves protocol details while keeping the path to working examples short.
If you are building a real-time system, SSE is a strong default for lightweight server push.