Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
12 Oct 2025 · 6 min read ·Article 104 / 125
Go

104 The gqlgen File Structure and How It Works

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

104 The gqlgen File Structure and How It Works

If you have ever built a GraphQL backend in Golang, you are surely familiar with gqlgen . This library offers a schema-first generator for GraphQL with a strongly typed workflow that integrates directly with Go idioms. This article will dissect the standard file structure of a gqlgen project, the inner workings of each component, along with examples and a simple request simulation. Let’s start by building a solid foundation in gqlgen.


Why gqlgen?

Gqlgen simplifies the process of building a GraphQL API in Golang with a schema-first workflow. You design the schema first, then gqlgen automatically generates the code stubs, so you can focus on the business logic.

The Schema-First Workflow in Brief

  1. Create a GraphQL schema (*.graphql).
  2. Run go run github.com/99designs/gqlgen generate.
  3. Implement the resolvers stubbed out by gqlgen.
  4. Run the server and start developing a robust GraphQL API.

The gqlgen File Structure

Let’s take a look at a typical gqlgen project structure, then break down the purpose of each piece.

text
 1.
 2├── go.mod
 3├── go.sum
 4├── gqlgen.yml
 5├── graph/
 6│   ├── generated/
 7│   │   ├── generated.go
 8│   │   └── models_gen.go
 9│   ├── model/
10│   │   └── models.go
11│   ├── resolver.go
12│   ├── schema.graphqls
13│   └── schema.resolvers.go
14├── server.go
15└── README.md

Explanation of the Structure

File/FolderDescription
go.mod, go.sumGo module dependency management.
gqlgen.ymlThe configuration file for gqlgen.
graph/generated/Code generated from the GraphQL schema (do not edit manually!).
graph/model/Go models that map to the GraphQL schema.
graph/resolver.goThe main struct that holds all the resolvers.
graph/schema.graphqlsThe GraphQL schema definition (Query, Mutation, Object type, etc.).
graph/schema.resolvers.goThe implementation of the GraphQL resolver functions (can be split across several files).
server.goInitializes and runs the server (usually with http.ServeMux or Gin, etc.).
README.mdThe project description document.

The gqlgen Workflow Diagram

To understand how the files integrate and how a GraphQL request flows, let’s visualize it with the following mermaid diagram:

MERMAID
flowchart TD
    A[Client] -->|Query/Mutation| B[HTTP Endpoint /graphql]
    B --> C[Server.go]
    C --> D[gqlgen Handler]
    D --> E[Generated Code (graph/generated)]
    E --> F[Resolver.go]
    F --> G[Business Logic in schema.resolvers.go / model/]
    G --> H[Data Source (DB/API)]
    H --> G
    G --> F
    F --> E
    E --> D
    D --> C
    C --> B
    B --> A

Description:
The client sends a Query/Mutation request to the /graphql endpoint, which is handled by the server and forwarded to the gqlgen handler. This handler leverages the generated code to validate the request and map it to the implemented resolvers. The resolver executes the business logic and fetches or modifies data from the data source before returning the response to the client.


1. Schema Definition: schema.graphqls

This file is the core foundation. Every GraphQL entrypoint, type, input, and even directives are written here.

Example:

graphql
 1# graph/schema.graphqls
 2
 3type Query {
 4  users: [User!]!
 5  user(id: ID!): User
 6}
 7
 8type Mutation {
 9  createUser(input: NewUser!): User!
10}
11
12type User {
13  id: ID!
14  name: String!
15  email: String!
16}
17
18input NewUser {
19  name: String!
20  email: String!
21}

2. Go Models: model/models.go

Optional – you can tailor your own Go models so they integrate with idiomatic Go code. If no model is provided, gqlgen will generate one automatically in generated/models_gen.go.

go
1// graph/model/models.go
2package model
3
4type User struct {
5    ID    string `json:"id"`
6    Name  string `json:"name"`
7    Email string `json:"email"`
8}

3. gqlgen Configuration: gqlgen.yml

This file specifies the schema reference, the output location for the generated code, model mapping, and more.

Example:

yaml
 1schema:
 2  - graph/schema.graphqls
 3
 4exec:
 5  filename: graph/generated/generated.go
 6  package: generated
 7
 8model:
 9  filename: graph/model/models.go
10  package: model
11
12resolver:
13  layout: follow-schema
14  dir: graph
15  package: graph
16
17models:
18  User:
19    model: graph/model.User
20  NewUser:
21    model: graph/model.NewUser

4. Generated Code: graph/generated/

Do not modify the contents of this folder. All files here are regenerated every time you run gqlgen generate.
This is where the binding between GraphQL operations and Go resolvers happens, along with compile-time type safety.


5. Resolvers: graph/resolver.go & schema.resolvers.go

resolver.go contains the main Resolver struct — this is usually where dependencies are injected (DB access, cache, and so on).

go
1type Resolver struct{
2    users []*model.User
3}

Meanwhile, schema.resolvers.go holds the implementation of each resolver (both generated and manual).

A Simple Resolver Example:

go
 1func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
 2    return r.users, nil
 3}
 4
 5func (r *mutationResolver) CreateUser(ctx context.Context, input model.NewUser) (*model.User, error) {
 6    user := &model.User{
 7        ID: fmt.Sprintf("%d", len(r.users)+1),
 8        Name: input.Name,
 9        Email: input.Email,
10    }
11    r.users = append(r.users, user)
12    return user, nil
13}

6. Server Entrypoint: server.go

Initializes and runs the GraphQL HTTP handler.

Example:

go
1func main() {
2    srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{users: []*model.User{}}}))
3    http.Handle("/graphql", srv)
4    log.Fatal(http.ListenAndServe(":8080", nil))
5}

Request-Response Simulation

For example, let’s create a new user in the GraphQL playground/batch.

Request:

graphql
1mutation {
2  createUser(input: {name: "Alice", email: "alice@example.com"}) {
3    id
4    name
5    email
6  }
7}
Response:
json
1{
2  "data": {
3    "createUser": {
4      "id": "1",
5      "name": "Alice",
6      "email": "alice@example.com"
7    }
8  }
9}


Practical Tips

  • Never edit files in the /generated folder; always modify code in /model and the resolvers.
  • Run go run github.com/99designs/gqlgen generate every time you change the schema.
  • Split resolvers across multiple files as the number of queries/mutations grows.
  • Take advantage of dependency injection on the Resolver struct to keep your logic from getting tangled.
  • Use a tool like GraphQL Playground for testing.

Summary

gqlgen designs a project structure that is highly idiomatic to Go and neatly separated:

  • Schema -> The central API contract that is generated directly into Go code stubs.
  • Models -> Can be customized.
  • Resolvers -> Where the core logic lives.
  • Generated Code -> The “bridge” between GraphQL and Go, which you never need to touch.

This way of clustering the gqlgen file structure helps keep your project scalable and maintainable. You still get the assurance of type safety and the ease of developing a GraphQL API in the Go ecosystem.

Happy exploring with gqlgen—with such a cohesive file architecture, building a Go GraphQL backend has never been this enjoyable and this safe! 🚀

Related Articles

💬 Comments