Skip to content
Back to skills

Channels

ASecurity

Common channel patterns and idioms

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added February 7, 2026
developmentgo

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add JamesPrial/claudefiles --skill channels --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Channels?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Channels
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jamesprial-channels/badge)](https://www.skillsdirectory.com/skills/jamesprial-channels)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: go-channel-patterns
description: Common channel patterns and idioms
---

# Channel Patterns

## Core Rule
**Only the sender closes channels.** Receivers never close.

## CORRECT - Sender closes
```go
func generator() <-chan int {
    ch := make(chan int)
    go func() {
        defer close(ch) // Sender closes
        for i := 0; i < 10; i++ {
            ch <- i
        }
    }()
    return ch
}

func main() {
    for num := range generator() {
        fmt.Println(num)
    }
}
```

## WRONG - Receiver closes
```go
func main() {
    ch := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            ch <- i // Panic: send on closed channel
        }
    }()

    for i := 0; i < 5; i++ {
        <-ch
    }
    close(ch) // WRONG: receiver closes
}
```

## Pattern: Fan-Out (Multiple Workers)
```go
func fanOut(input <-chan int, workers int) []<-chan int {
    outputs := make([]<-chan int, workers)
    for i := 0; i < workers; i++ {
        outputs[i] = worker(input)
    }
    return outputs
}

func worker(input <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range input {
            out <- n * 2
        }
    }()
    return out
}
```

## Pattern: Fan-In (Merge Channels)
```go
func fanIn(channels ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup

    wg.Add(len(channels))
    for _, ch := range channels {
        go func(c <-chan int) {
            defer wg.Done()
            for n := range c {
                out <- n
            }
        }(ch)
    }

    go func() {
        wg.Wait()
        close(out)
    }()

    return out
}
```

## Pattern: Or-Done (Early Exit)
```go
func orDone(ctx context.Context, ch <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for {
            select {
            case <-ctx.Done():
                return
            case v, ok := <-ch:
                if !ok {
                    return
                }
                select {
                case out <- v:
                case <-ctx.Done():
                    return
                }
            }
        }
    }()
    return out
}
```

## Rules
1. Use directional channels: `<-chan` (receive), `chan<-` (send)
2. Unbuffered for synchronization, buffered for non-blocking
3. Check `ok` when not using `range`: `v, ok := <-ch`
4. Close to signal "no more values", not to stop receivers
5. Nil channels block forever (useful in `select`)

## Buffered vs Unbuffered
```go
// Unbuffered: synchronous handoff
ch := make(chan int)

// Buffered: decouples sender/receiver
ch := make(chan int, 10)
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.