If you’ve ever wanted your server to push live updates to a browser without the client constantly polling, Server-Sent Events (SSE) are a simple and efficient solution. In this post, we’ll explore what SSE is, how to implement it in Golang, and why the client side requires EventSource.
I’ve also made a short video demo to show it in action, which you can check out below.
What is SSE?
SSE is a standard that allows a server to send continuous updates over a single HTTP connection to the client. Unlike WebSockets, SSE is unidirectional—the server sends data, but the client cannot push messages back on the same connection.
Common use cases:
- Live dashboards and monitoring systems.
- Chat notifications or social feed updates.
- Real-time logs or stock price tickers.
Creating an SSE Server in Go
Here’s how to implement a basic SSE server using Go:
package main
import (
"fmt"
"net/http"
"time"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
server := http.Server{
Addr: ":8080",
Handler: router,
}
router.HandleFunc("/sse", handleEvents).Methods("GET")
fmt.Println("SSE server running on :8080")
err := server.ListenAndServe()
if err != nil {
panic(err)
}
}
func handleEvents(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Fprintf(w, "data: %s\n\n", time.Now().String())
if f, ok := w.(http.Flusher); ok { f.Flush() }
case <-r.Context().Done():
return
}
}
}
Key points:
- Content-Type: text/event-stream is mandatory.
- Each message must start with data: and end with a double newline \n\n.
- Use
http.Flusher
to push data immediately without buffering.
The Client Side – EventSource
SSE is designed for browsers, which support a built-in EventSource API. This makes it very simple to receive server events:
<script>
const es = new EventSource("http://localhost:8080/sse");
es.onopen = () => console.log("SSE connected");
es.onmessage = e => console.log("message:", e.data);
es.onerror = e => console.error("SSE error", e);
</script>
- EventSource automatically reconnects if the connection drops.
- It parses data: messages sent by the server.
- This is why the client usually needs a browser or JS runtime that supports EventSource.
SSE vs Sockets
While SSE is perfect for server → client streaming, for bidirectional communication where the client also sends messages to the server in real time, WebSockets are more suitable.
SSE:
- Unidirectional (server → client)
- Works over HTTP/HTTPS
- Simpler to implement
WebSockets:
- Bidirectional
- More complex but flexible
- Great for chat apps, multiplayer games, and live collaboration tools
Quick Note on Streaming HTTP
SSE is a type of streaming HTTP, where the server sends data in chunks without closing the connection. Streaming HTTP itself is not limited to browsers and can be used in server-to-server communication as well.
Check Out the Video Demo
I’ve created a short video demonstrating how to implement SSE in Go, including the server code and how EventSource handles the data in a browser.
Conclusion:
SSE is a lightweight and efficient way to push live updates from servers to browsers. It’s simpler than WebSockets when you only need server-to-client communication, making it ideal for dashboards, logs, and notifications.
Top comments (2)
Clear and concise introduction to SSE! Consider adding a mention of reconnection logic and how to handle lost connections.
Thanks for the suggestion @gkoos. I will try to add that. Thanks again :)