Skip to content

prusov/gqldomainresolver

Repository files navigation

gqldomainresolver

CI Go Reference

A gqlgen plugin that splits resolvers into per-domain Go packages, so domain code no longer imports graph/generated.

Requires Go 1.26+. Licensed under MIT.

Why

Standard gqlgen puts every resolver in one package that imports graph/generated. On large schemas every edit invalidates a build artifact that can reach gigabytes — incremental compilation grinds to a halt.

How

The plugin produces a two-tier layout:

  • Tier 1 — root resolver package. Thin glue: Mutation() / Query() / Subscription() constructors, wrapper structs, embeds of the per-domain mixins. Methods reach callers via Go method promotion.
  • Tier 2 — per-domain packages. One package per subdirectory of graph/schema/. Real business logic lives here. These packages never import graph/generated — gqlgen interfaces are satisfied structurally.

A domain is the parent directory name of a .graphqls file: graph/schema/todos/todo.graphqls → domain todos. Files placed directly under graph/schema/ have no domain and stay in the root package.

Quick start (new project)

1. Install

go get github.com/prusov/gqldomainresolver

2. Custom gqlgen entry point

gqlgen's default go run github.com/99designs/gqlgen cannot load plugins:

// cmd/gqlgen/main.go
package main

import (
    "log"

    "github.com/99designs/gqlgen/api"
    "github.com/99designs/gqlgen/codegen/config"
    "github.com/prusov/gqldomainresolver"
)

func main() {
    cfg, err := config.LoadConfig("gqlgen.yml")
    if err != nil {
        log.Fatal(err)
    }
    plugin, err := gqldomainresolver.New()
    if err != nil {
        log.Fatal(err)
    }
    if err := api.Generate(cfg, api.AddPlugin(plugin)); err != nil {
        log.Fatal(err)
    }
}

New() with no options migrates every domain in the schema. New domains added later are picked up automatically.

3. Configure gqlgen.yml

The plugin ships its own safety-net resolver template and injects it into gqlgen automatically — no resolver_template entry is required, and the build no longer depends on go mod vendor or copying files out of the module cache.

# gqlgen.yml
resolver:
  layout: follow-schema
  dir: graph/resolver
  package: resolver

Setting resolver_template explicitly is still honoured if you need a custom template; the plugin yields to your override.

4. Write the root Resolver struct once

The plugin does not generate graph/resolver/resolver.go. Create it:

package resolver

type Resolver struct {
    DomainMutationResolvers
    DomainQueryResolvers
    DomainSubscriptionResolvers
}

Drop any embed whose root type your schema doesn't define.

5. Generate and fill in resolver bodies

go run ./cmd/gqlgen

Each domain gets graph/resolver/<domain>/*.resolvers.go with panic stubs. Replace each panic(...) with the real implementation — bodies are preserved across regeneration via AST extraction.

Migrating an existing project

Big-bang migration is impractical for any non-trivial codebase. The plugin supports incremental migration via WithEnabledDomains — wire the plugin in as a no-op first, then move one domain per PR. For projects that want the greenfield default minus a handful of large or in-flight domains, pair New() with WithExcludedDomains("...").

See MIGRATION.md for the full playbook.

Reference

Limitations

  • A given resolver field belongs to exactly one domain — splitting one root field across multiple domain packages isn't supported.
  • Only one plugin per gqlgen run can implement ResolverImplementer — don't combine with another plugin that hooks the same interface.
  • Two raw directory names that normalize to the same Go package (e.g. order-flow and order_flow) fail at codegen with a clear collision error. Rename one or pass WithKeywordPrefix to disambiguate.

About

gqlgen plugin that splits generated resolvers into per-domain Go packages. Eliminates the graph/generated import from domain code and keeps incremental compilation fast on large GraphQL schemas.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages