Source profileQuality 93/100

samber/cc-skills-golang/skills/golang-graphql/SKILL.md

golang-graphql

Implements GraphQL APIs in Golang using gqlgen or graphql-go. Apply when building GraphQL servers, designing schemas, writing resolvers, handling subscriptions, or integrating GraphQL with existing Go HTTP services. Also apply when the codebase imports `github.com/99designs/gqlgen` or `github.com/graph-gophers/graphql-go`.

Source repository stars
3,066
Declared platforms
2
Static risk flags
0
Last source update
2026-08-23
Source checked
2026-08-25

Decision brief

What it does: where it fits

Both major libraries are schema-first: write SDL (.graphql files), bind Go resolvers. Choose based on project size and team preferences.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexDeclaredSource recordInstall path and trigger
    Claude CodeDeclaredSource recordInstall path and trigger
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/samber/cc-skills-golang --skill "skills/golang-graphql"
    Safe inspection promptEditorial

    Inspect the Agent Skill "golang-graphql" from https://github.com/samber/cc-skills-golang/blob/a18860b303ef1d3d928f9670631e03210b8698bf/skills/golang-graphql/SKILL.md at commit a18860b303ef1d3d928f9670631e03210b8698bf. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      ✗ Bad — Int ID leaks implementation details, breaks client caching

      type Post { id: Int! } graphql type CreateUserPayload { user: User errors: [UserError!]! } go // ✓ Good — resolver delegates to service layer func (r mutationResolver) CreateUser(ctx context.Context, input model.CreateUserInput) (model.CreateUserPayload, error) { user, err := r.…

      gqlgen reference — codegen workflow, gqlgen.yml, DataLoaders, Federation v2, directivesgraphql-go reference — reflection resolver model, type mapping, tracingTesting — gqlgen client harness, gqltesting, httptest patterns
    2. 02

      Library Choice

      Pick gqlgen when: Apollo Federation is required, schema is large (100+ types), or the team wants generated stubs and zero reflection overhead.

      Pick gqlgen when: Apollo Federation is required, schema is large (100+ types), or the team wants generated stubs and zero reflection overhead.Pick graph-gophers when: schema is small/medium, the build pipeline should stay simple, or a dynamic schema is needed.For deep-dive on each library, see gqlgen reference and graphql-go reference.
    3. 03

      Schema Design

      Review the “Schema Design” section in the pinned source before continuing.

      Review and apply the “Schema Design” source section.
    4. 04

      ✓ Good — explicit nullability; ID scalar for opaque identifiers

      type User { id: ID! email: String! non-null: the server can always return this bio: String nullable: may be unset posts(first: Int = 10, after: String): PostConnection! }

      type User { id: ID! email: String! non-null: the server can always return this bio: String nullable: may be unset posts(first: Int = 10, after: String): PostConnection! }
    5. 05

      Resolver Patterns

      Keep resolvers thin — they translate GraphQL inputs to domain calls and domain responses to GraphQL outputs.

      Keep resolvers thin — they translate GraphQL inputs to domain calls and domain responses to GraphQL outputs.Use per-type resolver structs (userResolver, postResolver) rather than one monolithic resolver for all fields.

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score93/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars3,066SourceRepository attention, not individual Skill quality
    Compatibility2 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    samber/cc-skills-golang
    Skill path
    skills/golang-graphql/SKILL.md
    Commit
    a18860b303ef1d3d928f9670631e03210b8698bf
    License
    MIT
    Collected
    2026-08-25
    Default branch
    main
    View the original SKILL.md

    Persona: You are a Go GraphQL engineer. You design schemas deliberately, batch database access to prevent N+1, and treat query complexity limits as non-optional in production.

    Modes:

    • Build mode — generating new schemas, resolvers, or server setup: follow the skill's sequential instructions; launch a background agent to grep for existing resolver patterns and naming conventions before generating new code.
    • Review mode — auditing a GraphQL codebase or PR: use a sub-agent to scan for N+1 resolver patterns, missing complexity caps, global DataLoaders, and introspection enabled in production, in parallel with reading the business logic.

    Community default. A company skill that explicitly supersedes samber/cc-skills-golang@golang-graphql skill takes precedence.

    Go GraphQL Best Practices

    Both major libraries are schema-first: write SDL (.graphql files), bind Go resolvers. Choose based on project size and team preferences.

    This skill is not exhaustive. Refer to each library's official documentation and code examples for current API signatures. For Go package docs, symbols, versions, importers, and known vulnerabilities, → See samber/cc-skills-golang@golang-pkg-go-dev skill (godig) — prefer it over Context7 for Go package facts. To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See samber/cc-skills-golang@golang-gopls skill (gopls). Context7 remains a fallback for docs not indexed on pkg.go.dev.

    Library Choice

    LibraryApproachType safetyBuild stepBest for
    github.com/99designs/gqlgenCodegenCompile-timego generateLarge schemas, federation, strict types
    github.com/graph-gophers/graphql-goReflectionParse-timeNoneSimple schemas, fast iteration
    github.com/graphql-go/graphqlCode-firstRuntimeNoneAvoid — verbose, no SDL

    Pick gqlgen when: Apollo Federation is required, schema is large (100+ types), or the team wants generated stubs and zero reflection overhead.

    Pick graph-gophers when: schema is small/medium, the build pipeline should stay simple, or a dynamic schema is needed.

    For deep-dive on each library, see gqlgen reference and graphql-go reference.

    Schema Design

    # ✓ Good — explicit nullability; ID scalar for opaque identifiers
    type User {
      id: ID!
      email: String! # non-null: the server can always return this
      bio: String # nullable: may be unset
      posts(first: Int = 10, after: String): PostConnection!
    }
    
    # ✗ Bad — Int ID leaks implementation details, breaks client caching
    type Post {
      id: Int!
    }
    

    Nullability rule: mark a field ! only when the server can always return a value. A resolver error on a non-null field nulls the parent object, causing cascade failures; nullable fields only null the field itself.

    Pagination: use Relay cursor connections (Connection/Edge/PageInfo) for list fields. Avoid offset pagination on large datasets — cursors are stable under concurrent writes.

    Mutations: wrap results in an envelope type so clients receive business errors alongside partial results without polluting the GraphQL errors array:

    type CreateUserPayload {
      user: User
      errors: [UserError!]!
    }
    

    Resolver Patterns

    Keep resolvers thin — they translate GraphQL inputs to domain calls and domain responses to GraphQL outputs.

    // ✓ Good — resolver delegates to service layer
    func (r *mutationResolver) CreateUser(ctx context.Context, input model.CreateUserInput) (*model.CreateUserPayload, error) {
        user, err := r.userService.Create(ctx, input.Email, input.Name)
        if err != nil {
            return nil, formatError(err)
        }
        return &model.CreateUserPayload{User: toGQLUser(user)}, nil
    }
    
    // ✗ Bad — SQL in resolver, no separation of concerns
    func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
        row := r.db.QueryRowContext(ctx, "SELECT * FROM users WHERE id = $1", id)
        // ...
    }
    

    Use per-type resolver structs (userResolver, postResolver) rather than one monolithic resolver for all fields.

    N+1 Prevention (DataLoaders)

    Each User.posts resolver fires a SQL query per user without batching — O(n) DB calls for n users. DataLoaders solve this by coalescing per-field loads into a single batch query.

    Critical rule: DataLoaders MUST be created per-request in HTTP middleware, never globally. A global DataLoader caches across requests — stale data, potential cross-user data leakage.

    // ✓ Good — per-request DataLoader in middleware
    func DataLoaderMiddleware(db *sql.DB, next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            loaders := &Loaders{
                PostsByUserID: newPostsByUserIDLoader(r.Context(), db),
            }
            ctx := context.WithValue(r.Context(), loadersKey, loaders)
            next.ServeHTTP(w, r.WithContext(ctx))
        })
    }
    
    // ✗ Bad — global DataLoader shared across all requests
    var globalLoader = newPostsByUserIDLoader(context.Background(), db)
    

    In gqlgen, mark batched fields with resolver: true in gqlgen.yml to force a dedicated resolver method. See gqlgen reference for full DataLoader wiring.

    Authentication and Authorization

    Two-layer model:

    1. HTTP middleware — extract and validate tokens, stash identity in context.Context.
    2. Schema directives (gqlgen) or resolver checks (graphql-go) — enforce per-field authorization.
    // HTTP middleware layer (both libraries)
    func AuthMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            token := r.Header.Get("Authorization")
            user, err := validateToken(token)
            if err != nil {
                http.Error(w, "Unauthorized", http.StatusUnauthorized)
                return
            }
            ctx := context.WithValue(r.Context(), userKey, user)
            next.ServeHTTP(w, r.WithContext(ctx))
        })
    }
    

    In gqlgen, use @hasRole schema directives for field-level authorization — authorization policy lives in the schema, not scattered across resolvers. See gqlgen reference.

    Error Handling

    Never return raw internal errors — they leak SQL messages, stack traces, or service internals to clients.

    // gqlgen — custom ErrorPresenter strips internal details
    srv.SetErrorPresenter(func(ctx context.Context, err error) *gqlerror.Error {
        var gqlErr *gqlerror.Error
        if errors.As(err, &gqlErr) {
            return gqlErr // already formatted
        }
        // log internal err here
        return gqlerror.Errorf("internal error") // safe client message
    })
    
    // Add extension codes for client-side error handling
    return nil, &gqlerror.Error{
        Message: "user not found",
        Extensions: map[string]any{"code": "NOT_FOUND"},
    }
    

    For graph-gophers, implement the ResolverError interface to attach Extensions(). See graphql-go reference.

    Use graphql.AddError(ctx, err) in gqlgen for non-fatal field errors where the resolver can still return partial data.

    For error wrapping patterns, see the samber/cc-skills-golang@golang-error-handling skill.

    Subscriptions

    Subscriptions use long-lived WebSocket connections. The critical discipline: always respect context cancellation — a leaked goroutine per disconnected client exhausts resources silently.

    // ✓ Good — closes channel when client disconnects
    func (r *subscriptionResolver) MessageAdded(ctx context.Context, room string) (<-chan *model.Message, error) {
        ch := make(chan *model.Message, 1)
        sub := r.pubsub.Subscribe(room) // subscribe once before the goroutine
        go func() {
            defer close(ch) // always close; signals iteration to stop
            for {
                select {
                case <-ctx.Done():
                    return // client disconnected
                case msg := <-sub:
                    select {
                    case ch <- msg:
                    case <-ctx.Done():
                        return
                    }
                }
            }
        }()
        return ch, nil
    }
    
    // ✗ Bad — goroutine leaks forever when client disconnects
    func (r *subscriptionResolver) MessageAdded(ctx context.Context, room string) (<-chan *model.Message, error) {
        ch := make(chan *model.Message, 1)
        go func() {
            for msg := range r.pubsub.Subscribe(room) {
                ch <- msg // blocks forever after client gone
            }
        }()
        return ch, nil
    }
    

    Performance and Safety

    Production GraphQL servers require explicit limits. Without them, a single deeply nested query exhausts CPU and memory.

    // gqlgen — wire these into every production handler
    srv := handler.NewDefaultServer(es)
    srv.Use(extension.FixedComplexityLimit(200)) // max cost per query
    
    // Gate introspection — only in non-production environments
    if os.Getenv("ENV") != "production" {
        srv.Use(extension.Introspection{})
    }
    

    For graph-gophers: graphql.MaxDepth(10) and graphql.MaxParallelism(10) options at ParseSchema time.

    Query allow-listing: in production, consider persisted queries (gqlgen APQ extension) to reject arbitrary query strings.

    Common Mistakes

    MistakeWhy it mattersFix
    N+1 queries in child resolversOne SQL per parent row → O(n) DB callsUse per-request DataLoader
    Global DataLoaderCross-request cache — stale data, data leaksCreate DataLoader in request middleware
    Editing models_gen.go directlyNext go generate wipes hand editsUse autobind or models.<T>.model in gqlgen.yml
    Forgetting go generate after schema changeResolver interface mismatch at compile timeRe-run go tool gqlgen generate
    int field in graph-gophers resolverLibrary requires int32 for Int scalarUse int32 (or float64 for Float)
    Introspection enabled in productionExposes full schema to attackersGate with ENV check
    No complexity capDeeply nested query → CPU/memory DoSextension.FixedComplexityLimit(N)
    Leaking DB errors from resolversExposes SQL internals to clientsWrap in ErrorPresenter / ResolverError
    Subscription goroutine leakClient disconnect → goroutine runs foreverdefer close(ch) + select ctx.Done()
    Nullable field for always-required dataClients must null-check everywhereMark ! in schema; return error from resolver

    Deep Dives

    • gqlgen reference — codegen workflow, gqlgen.yml, DataLoaders, Federation v2, directives
    • graphql-go reference — reflection resolver model, type mapping, tracing
    • Testing — gqlgen client harness, gqltesting, httptest patterns

    Cross-References

    • → See samber/cc-skills-golang@golang-context skill for context propagation in resolvers and subscriptions
    • → See samber/cc-skills-golang@golang-error-handling skill for error wrapping and sentinel patterns
    • → See samber/cc-skills-golang@golang-testing skill for table-driven and integration test patterns
    • → See samber/cc-skills-golang@golang-observability skill for tracing and metrics in resolvers
    • → See samber/cc-skills-golang@golang-security skill for input validation and injection prevention
    • → See samber/cc-skills-golang@golang-database skill for N+1 query patterns and DataLoader database batching

    References

    If you encounter a bug or unexpected behavior in gqlgen, open an issue at https://github.com/99designs/gqlgen/issues.

    If you encounter a bug or unexpected behavior in graph-gophers/graphql-go, open an issue at https://github.com/graph-gophers/graphql-go/issues.

    Frequently asked questions

    What to verify before installation and use

    What does the golang-graphql source document cover?

    Both major libraries are schema-first: write SDL (.graphql files), bind Go resolvers. Choose based on project size and team preferences.

    How do I install golang-graphql?

    The source record exposes this install command: npx skills add https://github.com/samber/cc-skills-golang --skill "skills/golang-graphql". Inspect the command and pinned source before running it.

    Which Agent platforms does the source record declare?

    The pinned source record declares support for: codex, claude code.

    Alternatives

    Compare before choosing

    Computed 9980

    vasilyu1983/AI-Agents-public

    qa-testing-ios

    Guides iOS testing with XCTest, XCUITest, Swift Testing, simctl, and xcresult. Use when choosing destinations, controlling flakes, or parsing test artifacts for native apps.

    Computed 983,066

    samber/cc-skills-golang

    golang-samber-mo

    Monadic types for Golang using samber/mo — Option, Result, Either, Future, IO, Task, and State types for type-safe nullable values, error handling, and functional composition with pipeline sub-packages. Apply when using or adopting samber/mo, when the codebase imports `github.com/samber/mo`, or when considering functional programming patterns as a safety design for Golang.

    Computed 9880

    vasilyu1983/AI-Agents-public

    software-ui-ux-design

    Designs and audits UI/UX systems with usability and accessibility requirements. Use when shaping flows, design systems, interaction patterns, or WCAG-aware product behavior.

    Computed 973,066

    samber/cc-skills-golang

    golang-design-patterns

    Idiomatic Golang design patterns — functional options, constructors, error flow and cascading, resource management and lifecycle, graceful shutdown, resilience, architecture, dependency injection, data handling, streaming, and more. Apply when explicitly choosing between architectural patterns, implementing functional options, designing constructor APIs, setting up graceful shutdown, applying resilience patterns, or asking which idiomatic Go pattern fits a specific problem.