# How `wg.Go` Simplifies Concurrent Operations Compared to `sync.WaitGroup.Add/Done`

> Discover how wg.Go simplifies concurrent operations by automatically managing Add and Done, preventing deadlocks and reducing boilerplate compared to sync WaitGroup.

- Repository: [JetBrains/go-modern-guidelines](https://github.com/jetbrains/go-modern-guidelines)
- Tags: deep-dive
- Published: 2026-08-30

---

**`wg.Go` consolidates goroutine spawning and `sync.WaitGroup` lifecycle management into a single call, automatically handling `Add` and `Done` to eliminate boilerplate and prevent deadlocks.**

The `sync_waitgroup_go` guideline in the JetBrains/go-modern-guidelines repository recommends using `wg.Go` to streamline concurrent operations in Go. This pattern abstracts the manual counter increments and decrements required by `sync.WaitGroup`, significantly reducing repetitive code and the risk of synchronization bugs.

## Understanding the `sync_waitgroup_go` Guideline

According to the JetBrains/go-modern-guidelines source code, the guideline identifier **`sync_waitgroup_go`** explicitly states: *"Use `wg.Go` when spawning goroutines tracked by a `sync.WaitGroup`."*

This recommendation is documented across several key files:
- In [`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go), the test suite validates the guideline entry and its description.
- In [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go), the core logic loads and presents this recommendation to developers.
- In [`internal/guidelines/schema/schema.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/schema/schema.go), the JSON schema defines the structure for the `sync_waitgroup_go` rule, ensuring consistent documentation.

While the standard library `sync.WaitGroup` does not provide a built-in `Go` method, this guideline promotes adopting the pattern through third-party libraries such as `golang.org/x/sync/errgroup` or custom wrapper types.

## Manual Pattern vs. the `wg.Go` Approach

### Traditional `sync.WaitGroup` Implementation

The classic approach requires manually incrementing the counter before spawning a goroutine and ensuring `Done` is called within the goroutine, typically via `defer`.

```go
var wg sync.WaitGroup

for _, item := range items {
    wg.Add(1) // Explicit counter increment
    go func(i Item) {
        defer wg.Done() // Mandatory decrement
        process(i)
    }(item)
}

wg.Wait()

```

This pattern is verbose and error-prone. Forgetting `wg.Add(1)` causes premature termination, while omitting `defer wg.Done()` causes deadlocks.

### Streamlined Pattern with `wg.Go`

The `wg.Go` method wraps the goroutine creation and lifecycle management into one operation.

```go
var wg sync.WaitGroup // Assuming wg is a wrapper with Go method

for _, item := range items {
    wg.Go(func() {
        process(item)
    })
}

wg.Wait()

```

Here, the wrapper automatically calls the equivalent of `Add(1)` before launching the goroutine and guarantees `Done()` executes when the function returns, regardless of panics.

## Key Advantages for Concurrent Operations

- **Automatic Lifecycle Management**: The helper ensures the WaitGroup counter is incremented atomically before the goroutine starts and decremented upon completion, eliminating the manual `Add`/`Done` pairing.

- **Deadlock Prevention**: By guaranteeing that `Done` is called via deferred execution within the wrapper, `wg.Go` removes the risk of missing a decrement due to early returns, panics, or complex control flow.

- **Reduced Boilerplate**: Developers remove repetitive `defer wg.Done()` statements and explicit `Add` calls, shrinking code footprint and improving readability.

- **Panic Safety**: Implementations of `wg.Go` typically include `recover` mechanisms that ensure `Done` is called even if the goroutine panics, preventing the WaitGroup from waiting indefinitely on a crashed worker.

## Source Code References in JetBrains/go-modern-guidelines

The recommendation to prefer `wg.Go` over manual management is enforced through the repository's guideline infrastructure:

1. **[`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go)**: Contains the test validation for the `sync_waitgroup_go` guideline, ensuring the rule correctly identifies code that should use the `wg.Go` pattern.

2. **[`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go)**: Implements the logic that surfaces the guideline to analysis tools, mapping the identifier `sync_waitgroup_go` to its descriptive text about using `wg.Go` for goroutine tracking.

3. **[`internal/guidelines/schema/schema.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/schema/schema.go)**: Defines the parsed guideline structure, including fields for the rule ID (`sync_waitgroup_go`) and the recommendation to use `wg.Go` when spawning tracked goroutines.

## Summary

- **`wg.Go`** combines `Add`, goroutine creation, and `Done` into a single method call.
- The **`sync_waitgroup_go`** guideline in JetBrains/go-modern-guidelines explicitly recommends this pattern over manual `sync.WaitGroup` management.
- This approach eliminates the risk of mismatched `Add`/`Done` calls that lead to deadlocks or premature waits.
- The pattern is available via third-party libraries like `errgroup` or custom wrappers implementing the `Go(func())` signature.
- Key files documenting this include [`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go), [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go), and [`internal/guidelines/schema/schema.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/schema/schema.go).

## Frequently Asked Questions

### Is `wg.Go` part of the Go standard library?

No, `wg.Go` is not part of the standard `sync` package. As documented in the JetBrains guidelines, this method is provided by third-party libraries such as `golang.org/x/sync/errgroup` or implemented as a custom wrapper around `sync.WaitGroup` that exposes a `Go(func())` method.

### What happens if a goroutine panics when using `wg.Go`?

Robust implementations of `wg.Go` handle panics by using `defer` to call `Done` before executing the passed function. This ensures the WaitGroup counter is always decremented, preventing deadlocks even if the goroutine crashes, whereas manual `defer wg.Done()` patterns might be missed if placed after panic-triggering code.

### Can I use `wg.Go` with error handling patterns like `errgroup`?

Yes, the `errgroup.Group` type from `golang.org/x/sync/errgroup` implements a `Go` method that matches this pattern. It runs functions in goroutines while waiting for all to complete, and also captures the first non-nil error returned by any worker, combining the benefits of `wg.Go` with centralized error handling.

### Where is the `sync_waitgroup_go` guideline defined in the repository?

The guideline is defined in [`internal/guidelines/schema/schema.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/schema/schema.go) which structures the rule, loaded by [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go), and validated in [`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go). The identifier `sync_waitgroup_go` explicitly recommends using `wg.Go` when spawning goroutines tracked by a `sync.WaitGroup`.