blogs

November 17, 20252 min read

Let's understand Go Handle(r) family - last thing you need

Go Handler Family Diagram

Go Handler Family Diagram

When you begin writing HTTP servers in Go, the words Handler, HandlerFunc, Handle, and HandleFunc look confusing. They sound similar, but each plays a clear role. Once you see how they connect, everything becomes simple.

Go's HTTP system starts with the Handler interface. It has just one method:

code
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Any type that has this method becomes a Handler. For example, a struct can turn into a Handler like this:

code
type Hello struct {}

func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello from struct Handler"))
}

Now this struct can be registered in the router.

The next piece is HandlerFunc. This is not an interface. It is a function type:

code
type HandlerFunc func(ResponseWriter, *Request)

Go attaches a method to this function type:

code
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

This means any ordinary function with that signature automatically behaves like a Handler. Example:

code
func hello(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello"))
}

Because this function matches HandlerFunc, you can register it like this:

code
http.Handle("/hello", http.HandlerFunc(hello))

Or using the shorter helper:

code
http.HandleFunc("/hello", hello)

This is where newcomers get confused. The difference is simple:

Handle expects something that already implements the Handler interface.

HandleFunc expects a plain function, and Go converts it into a HandlerFunc automatically, which already has ServeHTTP.

So if you write a struct with ServeHTTP, use Handle:

code
http.Handle("/hi", Hello{})

If you write a simple function, use HandleFunc:

code
http.HandleFunc("/hi", hello)

Both eventually produce a Handler. The only difference is whether Go wraps it for you or you pass a Handler directly.

This entire design keeps Go's HTTP package clean and flexible. You can use functions, closures, or full struct-based handlers. Everything works because HandlerFunc turns a normal function into a real Handler by giving it the ServeHTTP method.

Once you understand that, the whole Handler family feels natural: Handler is the interface, HandlerFunc is a function type with ServeHTTP, and Handle/HandleFunc simply register your routes.

crafted by: atharva

Last visitor:

Pune, +IST
© 2025 Atharva Mhaske.