If you ever have the need to combine a plain HTTP webserver with a gRPC server on the same port, then you can use cmux to do so.

You can do something like:

package main

import (


func main() {

    // Create the listener
    l, err := net.Listen("tcp", ":8080")
    if err != nil {

    // Create a new cmux instance
    m := cmux.New(l)

    // Create a grpc listener first
    grpcListener := m.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"))

    // All the rest is assumed to be HTTP
    httpListener := m.Match(cmux.Any())

    // Create the servers
    grpcServer := grpc.NewServer()
    httpServer := &http.Server{}

    // Use an error group to start all of them
    g := errgroup.Group{}
    g.Go(func() error {
        return grpcServer.Serve(grpcListener)
    g.Go(func() error {
        return httpServer.Serve(httpListener)
    g.Go(func() error {
        return m.Serve()

    // Wait for them and check for errors
    err = g.Wait()  
    if err != nil {


This also demonstrates how the errgroup module can be used. The Wait method blocks until all function calls from the Go method have returned, then returns the first non-nil error (if any) from them.

PS: the example itself doesn't actually do something useful as we didn't register any gRPC functions neither did I define HTTP handlers.

Related Posts

  • Measure execution time
  • Read Suggestion: Using checksums to verify syncing 100M database records
  • Use Prefetch Objects to Control Your Prefetch Related
  • Looking up a CNAME in Go
  • How to test if __name__ == "__main__"