sync.WaitGroup

August 7, 2025

It’s been a year since my last live stream, as I was moving across the globe.

I’m finally settled (enough) to start up again.

Join me, as I’ll begin building a new feature in my open-source project. The next session will be August 15, at 19:00 UTC. Subscribe on YouTube and hit the Notify me button so you don’t miss it!


Yesterday we wrote some Go code to wait for goroutines using a channel:

done := make(chan struct{})

for i := range 10 {
	go func(i int) {
		fmt.Println(i)
		done <- struct{}{} // Signal that this goroutine is done
	}(i)
}

// Wait for all goroutines to finish
for range 10 {
	<-done
}

Today we’re going to modify this code to use sync.WaitGroup, which is a more idiomatic way to wait for multiple goroutines in Go.

The sync package provides a number of synchronization primitives. We’ll be looking specifically at the WaitGroup type for now, which provides three* methods:

  • Add(int): Increments the WaitGroup counter by the specified (possibly negative) number.
  • Done(): Decrements the WaitGroup counter by one. Equivalent to calling Add(-1).
  • Wait(): Blocks until the WaitGroup counter is zero.

*Go 1.25 will add a fourth, which we’ll discuss separately in the future.

Let’s update our code to use sync.WaitGroup:

wg := &sync.WaitGroup{}

for i := range 10 {
	wg.Add(1)
	go func(i int) {
		fmt.Println(i)
		wg.Done() // Signal that this goroutine is done
	}(i)
}

// Wait for all goroutines to finish
wg.Wait()

This code operates virtually identically to the previous version, but it’s arguably a bit more readable. You no longer have to manage a channel directly, and instead just increment and decrement the WaitGroup counter as goroutines start and finish. Then finally, we wait for all goroutines to finish by calling wg.Wait().

In the coming days we’ll explore some more advanced features of sync.WaitGroup.


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe