Choosing Between make and new in Go
Daniel Hayes
Full-Stack Engineer · Leapcell

Go language provides two commonly used ways to allocate memory: make
and new
. Although both are used for memory allocation, their roles and usage scenarios are quite different. Understanding the differences between these two is crucial for writing efficient and maintainable Go code. This article will thoroughly analyze the differences between make
and new
, their suitable scenarios, and offer some usage tips.
Basic Differences Between make
and new
new: Creates Zero Value of Pointer Types
new
is a keyword in Go used for memory allocation. Its function is to allocate a block of memory for a type and return a pointer to that memory. The memory allocated by new
is initialized to the zero value of the type.
Example: Using new
package main import "fmt" func main() { var p *int = new(int) fmt.Println(*p) // Output: 0, memory allocated for int by `new` is initialized to zero value }
- Return type:
new
returns a pointer to the type. - Zero value initialization:
new
initializes the allocated memory to the zero value of the type. For example, forint
type, the zero value is0
; forstring
type, it is an empty string""
.
make: Initializes Slices, Maps, and Channels
make
is a special built-in function in Go, specifically used to initialize three built-in data types: slice, map, and channel. Unlike new
, make
does not return a pointer to the allocated memory, but instead returns the initialized object itself.
Example: Using make
package main import "fmt" func main() { // Initialize slice s := make([]int, 5) fmt.Println(s) // Output: [0 0 0 0 0] // Initialize map m := make(map[string]int) m["age"] = 30 fmt.Println(m) // Output: map[age:30] // Initialize channel ch := make(chan int, 2) ch <- 1 fmt.Println(<-ch) // Output: 1 }
- Return type:
make
returns the object itself (slice, map, or channel), not a pointer. - Memory allocation and initialization:
make
not only allocates memory but also initializes the data structure itself. For example, when initializing a slice,make
allocates the underlying array and sets its length and capacity.
Main Differences Summary
-
Purpose:
new
: Allocates memory and returns a pointer to the type.make
: Initializes and returns a slice, map, or channel object.
-
Return Value:
new
: Returns a pointer to the type.make
: Returns the initialized object itself.
-
Applicable Types:
new
: All types.make
: Slice, map, and channel.
-
Initialization:
new
: Returns zero value.make
: Initializes according to the data structure’s type.
Tips for Using make
and new
Tips for Using new
Suitable for struct types:
new
is often used to allocate memory for structs and return pointers to them. It is important to note that the initial value of a struct pointer is the zero value of the struct.
Example: Using new
to allocate memory for a struct
type Person struct { Name string Age int } func main() { p := new(Person) fmt.Println(p) // Output: &{ 0} fmt.Println(p.Name) // Output: empty string fmt.Println(p.Age) // Output: 0 }
- Pointers created by
new
: Sincenew
returns a pointer to the struct, you can directly modify its fields withp.Name
orp.Age
.
Tips for Using make
Initialize slices with specified capacity:
make
can be used to initialize a slice with a specified length and capacity. Using make
, you can efficiently allocate the underlying array and initialize the slice.
Example: Using make
to initialize a slice with capacity
// Initialize a slice with length 5 and capacity 10 s := make([]int, 5, 10) fmt.Println(len(s), cap(s)) // Output: 5 10
- Specify map capacity during initialization: When creating a map with
make
, you can specify its initial capacity, which helps optimize performance by avoiding multiple memory expansions as elements are inserted.
Example: Using make
to initialize a map
m := make(map[string]int, 10) // Set initial capacity to 10 m["age"] = 30 m["height"] = 175 fmt.Println(m) // Output: map[age:30 height:175]
- Initialize buffered channels: Use
make
to create a buffered channel, specifying the channel’s buffer size. This is very useful in concurrent programming.
Example: Using make
to create a buffered channel
ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) // Output: 1
Choosing the Appropriate Memory Allocation Method
- Usage scenario for structs: If you only need a pointer to a struct and have no special requirements during initialization, using
new
is a simple and common approach. - Usage scenario for slices, maps, and channels: If you need to initialize a slice, map, or channel and may modify their contents,
make
is the more appropriate choice—especially when you need to specify capacity in advance.
Performance Considerations of make
and new
- Memory allocation overhead: When initializing slices, maps, and channels,
make
not only allocates memory but also performs type initialization, which may incur additional overhead. In contrast,new
only allocates memory and initializes it to the zero value, so its overhead is relatively small. - Avoid unnecessary memory allocations: For types such as slices, maps, or channels, it is recommended to specify an appropriate capacity when using
make
to reduce the number of memory reallocations.
Common Misuses
- Incorrectly using
new
to create slices or maps: Whennew
is used with slices, maps, or channels, it only returns the zero value of the type and does not perform initialization. Therefore, if you usenew
to create a slice, map, or channel and try to access its contents directly, it will result in a runtime error.
Incorrect example: Misusing new
to create a map
m := new(map[string]int) // Incorrect: returns a pointer, not an initialized map m["age"] = 30 // Runtime error: m is nil
Correct example: You should use make
to initialize a map.
m := make(map[string]int) m["age"] = 30
Summary
In Go, make
and new
are both keywords for memory allocation, and although their functions are similar, they have clear differences.
new
is used to allocate memory for a type and returns a pointer, and it is suitable for most types;
while make
is mainly used to initialize slices, maps, and channels, providing stronger initialization capabilities.
new
: Suitable for creating pointers to struct types and other basic types, and initializes the memory to the zero value.make
: Used to initialize slices, maps, and channels, supports specifying capacity, and completes internal initialization.
Understanding the different usage scenarios and performance impacts of these two will help you write more efficient and maintainable Go code.
We are Leapcell, your top choice for hosting Go projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ