If you already know channels in Go and buffered channels, this page focuses on a narrow question people search for: how to tell if a buffered channel’s queue is full or empty, or how to try a send without blocking. It also covers why unbuffered channels behave differently and why “check closed then write” is not something the language encourages.
Searches such as golang check if channel is full, golang check if channel is empty, golang channel length, or golang channel size all map to the same primitives: len, cap, and a select with default. For closed channels and sends, see the FAQ and the short section below—there is no race-free isClosed() helper in the standard story.
Tested with Go 1.26.4 linux/amd64 on Linux kernel 6.14.0-37-generic.
Buffered channels: len, cap, full, and empty
For ch := make(chan T, n) with n > 0, the channel has a buffer of size n. The language spec defines:
len(ch)— how many elements are queued in the buffer right now.cap(ch)— the buffer sizen(the maximumlencan reach before a send would block).
Empty buffer: len(ch) == 0 (nothing waiting to be received).
Full buffer: len(ch) == cap(ch) (no free slot; another send would block unless something receives first).
Those expressions are snapshots. Another goroutine can send or receive immediately after you read len, so use them when you already control concurrency or when a rough hint is enough—not as a substitute for a proper handoff protocol.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
fmt.Println("empty?", len(ch) == 0, "len", len(ch), "cap", cap(ch))
ch <- 1
fmt.Println("full?", len(ch) == cap(ch), "len", len(ch))
ch <- 2
fmt.Println("full?", len(ch) == cap(ch), "len", len(ch), "cap", cap(ch))
<-ch
fmt.Println("after one recv, full?", len(ch) == cap(ch), "len", len(ch))
}If you use Run on that snippet, the printed lines walk through empty vs full as values are sent and one is received—len reaches cap when both buffer slots hold values.
Try a send (or receive) without blocking: select and default
To detect “would this send block because the buffer is full?” without actually blocking, use select with a default branch. If the send cannot proceed immediately, control falls through to default.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
select {
case ch <- 3:
fmt.Println("sent 3")
default:
fmt.Println("send would block — buffer is full (for this moment)")
}
}With Run, the program takes the default branch and prints that the send would block because the buffer is full.
The same idea works for a non-blocking receive: select { case v := <-ch: ... default: ... }.
Unbuffered channels
For make(chan T) with no capacity argument, cap(ch) is 0 and len(ch) is 0 at all times. You cannot use len/cap to mean “full” or “empty” here—there is no buffer to measure. Use select with default if you need a non-blocking handshake, or redesign so a dedicated goroutine owns the channel end.
Closed channels, receives, and sends
To see whether a receive still delivers real data, use the comma-ok form:
v, ok := <-ch
if !ok {
// channel closed and drained (no more real values)
}There is no standard, race-free way to answer “is this channel closed?” right before a send. Sending on a closed channel panics. If you see searches like golang check if channel is closed before writing, the safe patterns are: one goroutine closes, others only send until they are told to stop (via another channel, context.Context, or shared state under a mutex)—not a pre-send isClosed() check.
Summary
On a buffered channel, golang channel length is len(ch) and golang channel size (buffer capacity) is cap(ch). Full means len(ch) == cap(ch); empty means len(ch) == 0. To react without blocking, use select with default. Unbuffered channels always report len 0 and cap 0, so those tests do not apply. Closed channels are observed from the receive side with v, ok := <-ch; avoid trying to “check closed” immediately before a send. For background on concurrency, see goroutines and golang concurrency.
References
- Length and capacity — Go spec
- Buffered channels — A Tour of Go
- Go channels article
- Functions in Go (for
len/capsyntax in general)

