Factory Function

In Go, because the language lacks traditional classes and constructors, factory functions are the idiomatic way to initialize and return instances of a type (usually a struct or interface). The struct itself may be filled with zero-values 1, partially or fully initialized. After the creation of the struct, the struct itself is ready to be used. We see this pattern a lot in the standard library and in the third-party libraries. It is one of the most widely used patterns in Go.

By convention, if a package exports only one main type, the function is usually named New(). If package exports multiple types, it follows the New<Type>() pattern. Below we have an example of a factory function that creates a new HTTP request. It uses the http.NewRequest() naming convention because the package itself contains multiple exported structs.

Example: factory function from the net/http package that creates a new HTTP request.

req, err := http.NewRequest("GET", "https://www.example.com", nil)
if err != nil {
    log.Fatal(err)
}

The factory function that returns a pointer should always return a pointer to the struct. The function should return an error if the struct initialization failed and in this case return nil pointer. If initialization was not successful, the struct should not be used.

Example: factory function that creates a new Robot struct. We are using the New() because the package contains only one exported type. Note that we are always returning a pointer to the struct, so we are avoiding possible nillability issues 2.

type Robot struct {
    Name string
}

func New(name string) *Robot {
    return &Robot{Name: name}
}

Example: This variation returns an interface instead of a concrete struct. This is powerful for encapsulation because it hides the internal implementation details of the package.

type Shape interface {
    Area() float64
}

// some implementation ommited...

func NewCircle(r float64) Shape {
    return circle{radius: r}
}

Example: This variation is used in the context of HTTP, we usually call this a closure-based handler or a handler factory. Instead of using global variables (which are hard to test and maintain), you “generate” a handler that has access to specific configurations or database connections.

func GreetHandlerGenerator(message string, showDebug bool) http.HandlerFunc {
	prefix := "[APP-V2]"
	return func(w http.ResponseWriter, r *http.Request) {
	  // do something with the request and the prefix...
	}
}

Example: A Must naming convention is used for factory functions that panic instead of returning an error. You will typically see this when a failure to initialize is considered a “fatal” error that makes the application impossible to run. if you are initializing something at the very start of your program (like a compiled regular expression, a template, or a database connection string), and that initialization fails, your program usually can’t proceed anyway. Packages can support both naming conventions the New() and the Must().

var re = regexp.MustCompile(`^[a-z]+$`)

If Your factory function has more than three arguments, consider using a builder pattern 3 or one of the functional options patterns 4 or 5.

Copyright © 2026 by Michal Przybylowicz