Go by Example: Buffered Channels
Explore Buffered Channels in Go. Unlike unbuffered channels, buffered channels have a capacity and can accept values without a corresponding receiver up to a limit. This example shows how to create them and explains their non-blocking behavior when space is available.
Code
package main
import "fmt"
func main() {
// Create a buffered channel with capacity 2
messages := make(chan string, 2)
// Sends don't block because there is space
messages <- "buffered"
messages <- "channel"
// Receive values
fmt.Println(<-messages)
fmt.Println(<-messages)
}Explanation
Buffered channels in Go provide asynchronous communication between goroutines by introducing a queue that can hold a fixed number of values before send operations block. Unlike unbuffered channels where sends and receives must happen simultaneously (synchronous handoff), buffered channels allow senders to continue working even when no receiver is immediately ready, up to the buffer's capacity.
When you create a buffered channel with make(chan Type, capacity), the second argument specifies how many values the channel can hold. Send operations (ch <- value) will only block when the buffer is full. Receive operations (<-ch) will only block when the buffer is empty.
- Capacity: The number of elements the channel can hold (queue size).
- Non-blocking Sends: Sending is non-blocking as long as the buffer isn't full.
- Decoupling: Allows producers and consumers to operate at different rates temporarily.
- Blocking: Blocks only when full (on send) or empty (on receive).
However, buffered channels are not a simple performance optimization—they change the concurrency semantics of your program. Improper buffer sizing can lead to deadlocks or memory waste.

