Skip to main content
rule

go · sanjeed5 — Cursor rule: what it does, how to install

Go coding guidelines for Cursor based on Google's style recommendations. Enforces explicit error wrapping, memory efficiency, and clear package boundaries.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/go.mdc
Open on GitHub

What go does

This rule configures Cursor to generate Go code aligned with Google's style standards. It forbids vague utility namespaces like util or common. Domain code must be divided into focused packages or hidden inside the internal directory to prevent unwanted imports.

Error handling follows explicit chaining. Failures must be wrapped with %w using fmt.Errorf, while inspections rely strictly on errors.Is and errors.As. To minimize garbage collector pressure, the instructions mandate pre-allocating slice capacities, using strings.Builder with pre-allocated size, and passing small structs by value.

Concurrency rules require context.Context as the first parameter for I/O and long operations. For running multiple goroutines, the rule depends on golang.org/x/sync/errgroup.

What it helps with

  • eliminate catch-all util packages using clear domain boundaries
  • preserve error type inspection chains with %w
  • reduce GC overhead by pre-allocating slices and map capacities
  • manage goroutine cancellation cleanly with errgroup.Group

Example prompts for the agent

  • Write an HTTP client function accepting context.Context with cancellation support.
  • Concatenate string values inside a loop using strings.Builder and Grow.
  • Create an internal auth service package that wraps database errors using %w.

How to install go

Manually: put the files in place

.cursor/rules/go.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about go

How to install the go rule in Cursor?

Add the rule configuration to .cursor/rules/go.mdc in your project root. Cursor will automatically read the instructions for all files across the project.

What does the go rule do?

It guides Cursor to produce idiomatic Go code. The instructions focus on clean package structure, zero unnecessary allocations in hot paths, and traceable error chains.

Does this rule require external dependencies?

Yes, concurrent task orchestration requires golang.org/x/sync/errgroup. Other guidelines rely entirely on Go's standard library.

Source text

go.mdc · CC0-1.0
---
description: Definitive guidelines for writing clear, simple, performant, and maintainable Go code, adhering to Google's style and modern best practices.
globs: **/*
---
# Go Best Practices

This guide outlines our team's definitive Go coding standards, emphasizing clarity, simplicity, performance, and maintainability. Adhere to these principles to ensure a consistent, high-quality codebase that aligns with Google's Go Style Guide.

## 1. Code Organization & Structure

**Prioritize clarity and discoverability.** Structure your projects logically, making it easy for new team members to understand the codebase.

### Package Naming & Purpose
Packages must have short, lowercase names that clearly describe their single purpose. Avoid generic names like `util` or `common`.

❌ BAD:
```go
// myproject/utils/string_helpers.go
package utils // Too generic, doesn't describe specific utility

func SanitizeString(s string) string { /* ... */ }
```

✅ GOOD:
```go
// myproject/text/sanitizer.go
package text // Clear domain, specific functionality

func Sanitize(s string) string { /* ... */ }
```

### `internal` Package for Encapsulation
Always use the `internal` directory for code that should not be imported by other projects or external modules. This enforces strong encapsulation and prevents unintended dependencies.

❌ BAD:
```go
// myproject/service/auth.go (Exposes internal logic to external consumers)
package service

type AuthService struct { /* ... */ }
```

✅ GOOD:
```go
// myproject/internal/auth/service.go (Only importable by modules within 'myproject')
package auth

type Service struct { /* ... */ }
```

## 2. Error Handling

**Handle errors explicitly and provide actionable context.** Never ignore errors. Use `errors.Is` and `errors.As` for robust error inspection.

### Wrap Errors with Context
Always wrap errors to add context, making debugging easier and preserving the error chain. Use `%w` with `fmt.Errorf` to enable `errors.Is` and `errors.As`.

❌ BAD:
```go
if err := db.Save(user); err != nil {
    return fmt.Errorf("failed to save user: %v", err) // Loses original error type
}
```

✅ GOOD:
```go
if err := db.Save(user); err != nil {
    return fmt.Errorf("failed to save user %s: %w", user.ID, err) // Original error preserved
}
```

### Use `errors.Is` and `errors.As` for Inspection
For checking specific error types or values, use `errors.Is` for direct comparison and `errors.As` for unwrapping to a specific error type. This works correctly with wrapped errors.

❌ BAD:
```go
if err == sql.ErrNoRows { // Fails if error is wrapped by fmt.Errorf
    return ErrNotFound
}
if _, ok := err.(*MyCustomError); ok { // Fails if error is wrapped
    // ...
}
```

✅ GOOD:
```go
if errors.Is(err, sql.ErrNoRows) { // Correctly identifies sql.ErrNoRows in chain
    return ErrNotFound
}
var customErr *MyCustomError
if errors.As(err, &customErr) { // Correctly unwraps to MyCustomError
    // ...
}
```

## 3. Performance Considerations

**Minimize allocations and GC pressure.** Go's GC is efficient, but excessive allocations will always be a bottleneck in hot paths.

### Pre-allocate Slices and Maps
Always pre-allocate slices and maps with known or estimated capacities to avoid repeated reallocations and garbage generation.

❌ BAD:
```go
var results []Result // Grows dynamically, causing multiple reallocations
for _, item := range items {
    results = append(results, process(item))
}
```

✅ GOOD:
```go
results := make([]Result, 0, len(items)) // Pre-allocate capacity
for _, item := range items {
    results = append(results, process(item))
}
```

### Use `strings.Builder` for String Concatenation
Avoid `+` or `fmt.Sprintf` in loops for building strings. `strings.Builder` minimizes allocations by writing to a single underlying buffer.

❌ BAD:
```go
var s string
for i := 0; i < 1000; i++ {
    s += strconv.Itoa(i) + "," // Creates many intermediate string allocations
}
```

✅ GOOD:
```go
var sb strings.Builder
sb.Grow(1000 * 5) // Estimate required size to avoid initial reallocations
for i := 0; i < 1000; i++ {
    sb.WriteString(strconv.Itoa(i))
    sb.WriteString(",")
}
s := sb.String()
```

### Leverage `sync.Pool` for Reusable Objects
For frequently created and discarded objects (e.g., HTTP request buffers, database connections), use `sync.Pool` to reduce GC overhead by reusing objects.

❌ BAD:
```go
func handleRequest(w http.ResponseWriter, r *http.Request) {
    buf := make([]byte, 4096) // New allocation per request
    // ... use buf ...
}
```

✅ GOOD:
```go
var bufferPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 4096) // Allocate new buffer if pool is empty
    },
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    buf := bufferPool.Get().([]byte) // Get a buffer from the pool
    defer bufferPool.Put(buf)        // Return buffer to pool when done
    // ... use buf ...
}
```

### Pass Small Structs by Value
For small, immutable structs (e.g., coordinates, simple IDs), passing by value can avoid heap allocations and improve cache locality, as determined by escape analysis.

❌ BAD:
```go
type Point struct { X, Y int }
func movePoint(p *Point, dx, dy int) { // Pointer might force heap allocation
    p.X += dx
    p.Y += dy
}
```

✅ GOOD:
```go
type Point struct { X, Y int }
func movePoint(p Point, dx, dy int) Point { // Value type, likely stack allocated
    p.X += dx
    p.Y += dy
    return p
}
```

## 4. Concurrency & Context

**Manage goroutines and resource lifetimes effectively.** Always use `context.Context` for cancellation and timeouts.

### Use `context.Context` for Cancellation and Timeouts
Pass `context.Context` as the first argument to functions that perform I/O or long-running operations. This enables graceful shutdown and resource management.

❌ BAD:
```go
func fetchData(url string) ([]byte, error) {
    // No way to cancel or set a timeout for the HTTP request
}
```

✅ GOOD:
```go
func fetchData(ctx context.Context, url string) ([]byte, error) {
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
    if err != nil {
        return nil, fmt.Errorf("failed to create request: %w", err)
    }
    resp, err := http.DefaultClient.Do(req) // Respects context cancellation/timeout
    if err != nil {
        return nil, fmt.Errorf("http request failed: %w", err)
    }
    defer resp.Body.Close()
    return io.ReadAll(resp.Body)
}
```

### Coordinate Goroutines with `errgroup.Group`
For managing multiple goroutines that need to complete or be cancelled together, use `golang.org/x/sync/errgroup`. This simplifies error propagation and context cancellation across concurrent tasks.

❌ BAD:
```go
var wg sync.WaitGroup
var mu sync.Mutex
var errors []error // Manual error collection

for _, task := range tasks {
    wg.Add(1)
    go func(t Task) {
        defer wg.Done()
        if err := t.Run(); err != nil {
            mu.Lock()
            errors = append(errors, err)
            mu.Unlock()
        }
    }(task)
}
wg.Wait()
// Manual error checking and potential resource leaks on first error
```

✅ GOOD:
```go
group, ctx := errgroup.WithContext(context.Background()) // Context for cancellation
// var results []Result // Use a channel or mutex-protected slice if results are needed

for _, task := range tasks {
    task := task // Capture loop variable for closure
    group.Go(func() error {
        select {
        case <-ctx.Done(): // Respect cancellation from other goroutines
            return ctx.Err()
        default:
            if err := task.Run(ctx); err != nil { // Pass context to task
                return fmt.Errorf("task %s failed: %w", task.ID, err)
            }
            return nil
        }
    })
}

if err := group.Wait(); err != nil { // Waits for all, returns first non-nil error
    log.Printf("One or more tasks failed: %v", err)
}
```

## 5. API Design

**Design clear, intuitive, and idiomatic APIs.** Follow Go's conventions for function signatures and return values.

### Idiomatic Function Signatures
Prefer `(value, error)` return patterns. Avoid naked returns and ensure clarity in parameter order (e.g., `context.Context` first, then inputs, then options).

❌ BAD:
```go
func GetUser(id string) (user User, err error) { // Naked return, less clear
    // ...
    return
}
```

✅ GOOD:
```go
func GetUser(ctx context.Context, id string) (User, error) { // Clear return, context first
    // ...
    return user, nil
}
```

### Accept Interfaces, Return Structs
This principle promotes flexibility for callers (they can pass any type satisfying the interface) while maintaining concrete implementation details internally.

❌ BAD:
```go
func Process(reader *bytes.Reader) error { // Too specific, limits caller flexibility
    // ...
}
```

✅ GOOD:
```go
func Process(reader io.Reader) error { // Accepts any io.Reader, highly flexible
    // ...
}
```

## 6. Testing Approaches

**Write comprehensive, fast, and maintainable tests.** Prioritize table-driven tests for clarity and coverage.

### Table-Driven Tests
Use table-driven tests for functions with multiple inputs and expected outputs. This reduces boilerplate, improves readability, and makes it easy to add new test cases.

❌ BAD:
```go
func TestAdd(t *testing.T) {
    if Add(1, 2) != 3 {
        t.Errorf("Add(1, 2) = %d; want 3", Add(1, 2))
    }
    if Add(-1, 1) != 0 {
        t.Errorf("Add(-1, 1) = %d; want 0", Add(-1, 1))
    }
}
```

✅ GOOD:
```go
func TestAdd(t *testing.T) {
    tests := []struct {
        name string
        a, b int
        want int
    }{
        {"positive numbers", 1, 2, 3},
        {"negative and positive", -1, 1, 0},
        {"zero", 0, 0, 0},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) { // Use t.Run for isolated subtests
            if got := Add(tt.a, tt.b); got != tt.want {
                t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
            }
        })
    }
}
```

## 7. Security Best Practices

**Integrate security from the start.** Always validate inputs and handle sensitive data carefully.

### Input Validation
Never trust user input. Validate all inputs at the API boundary to prevent injection attacks, buffer overflows, and other vulnerabilities.

❌ BAD:
```go
func createUser(username string) error {
    // Directly uses username from request without validation
    db.CreateUser(username)
}
```

✅ GOOD:
```go
func createUser(username string) error {
    if !isValidUsername(username) { // Validate length, allowed characters, format
        return errors.New("invalid username format")
    }
    db.CreateUser(username)
}
```

### Secure Dependency Management
Regularly audit and update dependencies to mitigate known vulnerabilities. Use `go mod tidy` to clean up unused modules and `govulncheck` to identify issues.

❌ BAD:
```go
// Relying on old, potentially vulnerable dependencies without checks
```

✅ GOOD:
```go
// Keep go.mod clean and dependencies updated.
// Use `go get -u ./...` and `go mod tidy`.
// Regularly run `govulncheck ./...` to identify known vulnerabilities.
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Similar IDE rules

All IDE rules for Backend and APIs →

go by other authors comes first.

go official github Enforces idiomatic Go practices based on Effective Go and the Google style guide. It keeps package structures clean and avoids nested branching. ★ 40,478repo stars go PatrickJS This rule guides Cursor toward idiomatic Go with explicit errors, interface-based design, and context-aware concurrency. It targets .go files. ★ 41,028repo stars golang-design-patterns samber This skill guides idiomatic Go design for APIs, resource lifecycles, graceful shutdown, and architecture. Use it when designing or reviewing Go code. CX Codex +1 42,100installs golang-performance samber Guides AI coding agents through profiling, memory allocation cuts, and CPU optimization in Go projects using a strict measurement-first cycle. CX Codex +1 41,900installs error-handling affaan-m A skill that sets one way to handle errors in TypeScript, Python and Go: typed errors, retries, circuit breakers, user-facing messages. CX Codex +1 4,800installs code-craft jssblck code-craft guides type boundaries, invariants, state, effects, errors, and abstraction choices. Use it when an agent is shaping a code change. CX Codex +1 1,700installs go-error-handling cxuu Guides coding agents on idiomatic Go error handling, covering sentinel errors, error wrapping with %w or %v, and clean error flow. CX Codex +1 1,300installs go-control-flow cxuu Teaches AI agents canonical Go control flow patterns: early returns, scoped if statements, and for loops. Keeps code flat and avoids variable shadowing bugs. CX Codex +1 1,200installs

From the same set240

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor