One of the first real design questions you hit in Go is:
Should this method use a value receiver or a pointer receiver?
You’ll see both forms everywhere:
func (u User) Greet() {}
and
func (u *User) UpdateName() {}
They look similar, but the choice matters for correctness, performance, and how your types behave in real backend code.
Let’s break it down properly.
What is a Receiver?
In Go, a method is just a function attached to a type.
type User struct {
Name string
}
Now we add behavior:
func (u User) Greet() {
fmt.Println("Hello,", u.Name)
}
The u here is called the receiver. It’s the value the method operates on.
You call it like this:
user := User{Name: "Shivam"}
user.Greet()
So far so good.
Value Receiver: The Method Gets a Copy
When you write:
func (u User) ChangeName() {
u.Name = "New Name"
}
The method receives a copy of the struct.
That means it can read the data, but if it modifies the receiver, it’s only modifying the copy.
Example:
type User struct {
Name string
}
func (u User) ChangeName() {
u.Name = "New Name"
}
func main() {
user := User{Name: "Shivam"}
user.ChangeName()
fmt.Println(user.Name)
}
Output:
Shivam
Nothing changed, because the method was working on a copy.
This is the most important thing to understand:
Value receiver means “work on a copy”.
Pointer Receiver: The Method Works on the Original
Now compare that with:
func (u *User) ChangeName() {
u.Name = "New Name"
}
Here the receiver is a pointer, so the method has access to the original struct in memory.
Example:
type User struct {
Name string
}
func (u *User) ChangeName() {
u.Name = "New Name"
}
func main() {
user := User{Name: "Shivam"}
user.ChangeName()
fmt.Println(user.Name)
}
Output:
New Name
This time the change sticks, because pointer receivers modify the real object.
Pointer receiver means “work on the original”.
When Should You Use Pointer Receivers?
In production Go code, pointer receivers are the default for most structs.
You want pointer receivers when the method needs to modify state. Any method that updates fields should almost always be a pointer receiver.
They’re also important for performance. If your struct is large, using value receivers means copying it every time you call a method. Pointer receivers avoid that copy.
Another big reason is interfaces. In Go, methods with pointer receivers belong only to the pointer type, not the value type. That affects whether your type satisfies an interface, which matters a lot in backend systems.
When Are Value Receivers Fine?
Value receivers are good when the struct is small and the method doesn’t need to modify anything.
A common example is something like a Point type or a read-only helper method.
func (p Point) Distance() float64
If the method is purely about reading data, value receivers are clean and safe.
One Practical Rule That Works Most of the Time
If your type represents something real in a backend system (service, handler, config, DB model, controller), use pointer receivers.
If your type is small and behaves like a simple value, value receivers are fine.
When in doubt, pointer receivers are usually the right choice.
Simply
Value receiver: method works on a copy.
Pointer receiver: method works on the original.
That’s the whole difference, and once you internalize it, Go method design becomes straightforward.
Top comments (0)