Skip to content

Strapi GraphQL Setup — Install Plugin, Schema Generation, Queries and Mutations

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will install Strapi's Graphql plugin, explore the auto-generated GraphQL schema, and write queries and mutations to fetch and manipulate your content with the flexibility that GraphQL provides over REST.

What You'll Learn

  • How to install the GraphQL plugin via command line and admin panel
  • How GraphQL schema is auto-generated from your content types
  • How to write queries with filtering, sorting, and population
  • How to write mutations for creating, updating, and deleting content
  • How to use the GraphQL playground for testing
  • GraphQL-specific features like fragments and aliases

Why It Matters

GraphQL gives frontend teams complete control over what data they fetch. Instead of the REST approach where the server decides the response shape, GraphQL lets the client request exactly what it needs. This eliminates over-fetching (too much data) and under-fetching (too little data), making frontends faster and more maintainable.

Real-World Use

A product listing page needs product name, price, and thumbnail. The product detail page needs name, price, description, images, reviews, and related products. With REST, you would need two endpoints or accept that the list endpoint returns too much data. With GraphQL, the same endpoint handles both — the frontend requests only what it needs for each page.

Learning Path

flowchart LR
  A["REST API"] --> B["API Parameters"]
  B --> C["GraphQL Setup
-- You are here"]:::current C --> D["API Customization"] D --> E["API Security"] classDef current fill:#4945ff,color:#fff,stroke-width:2px

Installing the GraphQL Plugin

The GraphQL plugin is separate from Strapi core. You install it like any other plugin.

# Install using the Strapi CLI
npm run strapi install graphql

# Or install via npm directly
npm install @strapi/plugin-graphql

# After installation, rebuild the admin panel
npm run build

After installation, the GraphQL endpoint is available at http://localhost:1337/graphql. Strapi also adds a GraphQL playground (if enabled in development) where you can test queries.

To verify the installation:

# Test the GraphQL endpoint
curl -X POST http://localhost:1337/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __schema { types { name } } }"}'

The response includes the complete GraphQL schema with all your content types reflected as queryable types.

Auto-Generated Schema

Strapi automatically generates a GraphQL schema from your content types. Every collection type and single type becomes a GraphQL type.

For a content type "Article" with fields title, content, and author, Strapi generates:

type Article {
  id: ID!
  title: String
  content: String
  author: Author
  createdAt: DateTime
  updatedAt: DateTime
  publishedAt: DateTime
}

type ArticleEntity {
  id: ID!
  attributes: Article!
}

type ArticleEntityResponse {
  data: ArticleEntity
}

type ArticleEntityResponseCollection {
  data: [ArticleEntity!]!
  meta: ResponseMeta!
}

The naming convention follows: {ContentType}, {ContentType}Entity, {ContentType}EntityResponse, and {ContentType}EntityResponseCollection.

Writing Queries

GraphQL queries fetch data. Here is how the REST equivalents translate to GraphQL:

# Equivalent to GET /api/articles
query {
  articles {
    data {
      id
      attributes {
        title
        content
        createdAt
      }
    }
    meta {
      pagination {
        total
        page
        pageSize
      }
    }
  }
}

# Equivalent to GET /api/articles/1
query {
  article(id: 1) {
    data {
      id
      attributes {
        title
        content
      }
    }
  }
}

The id field is at the same level as attributes, not inside it. This mirrors the REST API response structure.

Filtering and Sorting in GraphQL

GraphQL uses named arguments for filtering and sorting:

# Filtering with operators
query {
  articles(
    filters: {
      title: { containsi: "strapi" }
      createdAt: { gte: "2026-01-01" }
    }
  ) {
    data {
      id
      attributes { title }
    }
  }
}

# Sorting
query {
  articles(sort: ["createdAt:desc", "title:asc"]) {
    data {
      id
      attributes { title createdAt }
    }
  }
}

# Pagination
query {
  articles(pagination: { page: 1, pageSize: 10 }) {
    data {
      id
      attributes { title }
    }
    meta {
      pagination {
        total
        pageCount
      }
    }
  }
}

GraphQL operators follow the same names as REST but in camelCase: containsi, eq, ne, gt, gte, lt, lte, in, notIn, null, notNull.

Populating Relations in GraphQL

In GraphQL, you access relations by adding their fields to the query:

# Populate author relation
query {
  articles {
    data {
      id
      attributes {
        title
        author {
          data {
            id
            attributes {
              name
              email
            }
          }
        }
      }
    }
  }
}

# Deeply nested population
query {
  articles {
    data {
      attributes {
        title
        author {
          data {
            attributes {
              name
              articles {
                data {
                  attributes { title }
                }
              }
            }
          }
        }
      }
    }
  }
}

GraphQL population is natural — you just query the fields you want. The nesting is unlimited (within practical performance limits).

Writing Mutations

Mutations create, update, and delete data:

# Create an article
mutation {
  createArticle(data: {
    title: "New Article"
    content: "Content here"
    author: 1
  }) {
    data {
      id
      attributes {
        title
        createdAt
      }
    }
  }
}

# Update an article
mutation {
  updateArticle(
    id: 1
    data: {
      title: "Updated Title"
    }
  ) {
    data {
      id
      attributes { title }
    }
  }
}

# Delete an article
mutation {
  deleteArticle(id: 3) {
    data {
      id
      attributes { title }
    }
  }
}

The mutation names follow the pattern create{ContentType}, update{ContentType}, and delete{ContentType}.

Using the GraphQL Playground

When the plugin is installed, you can access the GraphQL playground at http://localhost:1337/graphql. The playground provides:

  • A query editor with syntax highlighting
  • Schema documentation browser
  • Query history
  • Response viewer

The playground is enabled in development mode by default. In production, disable it by setting apolloServer.introspection to false in the plugin configuration.

// config/plugins.js
module.exports = {
  graphql: {
    config: {
      endpoint: "/graphql",
      shadowCRUD: true,
      apolloServer: {
        introspection: process.env.NODE_ENV === "development",
      },
    },
  },
};

GraphQL Fragments

Fragments let you reuse field selections across multiple queries:

# Define a fragment
fragment ArticleFields on Article {
  title
  content
  createdAt
  author {
    data {
      attributes {
        name
      }
    }
  }
}

# Use the fragment
query {
  articles {
    data {
      id
      attributes {
        ...ArticleFields
      }
    }
  }
}

fragment ArticleFields on Article {
  title
  content
  createdAt
  author {
    data {
      attributes {
        name
      }
    }
  }
}

Fragments keep your queries DRY. When you need to adjust the fields, you change the fragment once instead of every query.

Common Mistakes

  1. Requesting all fields without thinking. GraphQL makes it easy to request every available field. This can create massive responses. Only request the fields your component actually renders.

  2. Nesting queries too deeply. GraphQL queries with 5+ levels of nested relations generate many database queries. Monitor performance and limit nesting depth.

  3. Forgetting the data wrapper nesting. The response structure is data -> id and data -> attributes -> fields. Newcomers often look for fields directly on the data level.

  4. Not using query variables. Hardcoding values in queries makes them inflexible and unsafe. Use variables for dynamic values like IDs and filter inputs.

  5. Leaving the playground enabled in production. The playground exposes your full schema to anyone who visits the endpoint. Disable introspection in production for security.

Practice Questions

  1. Write a GraphQL query that fetches the title and author name of the 5 most recent articles. Answer: query { articles(sort: ["createdAt:desc"], pagination: { pageSize: 5 }) { data { id attributes { title author { data { attributes { name } } } } } } }

  2. How do you create a new article with a relation to an existing author using GraphQL? Answer: Use the createArticle mutation with the author ID: mutation { createArticle(data: { title: "...", content: "...", author: 1 }) { data { id } } }

  3. What is the benefit of using fragments in GraphQL? Answer: Fragments let you define a set of fields once and reuse them across multiple queries. Changes to the fragment automatically apply to all queries that use it, keeping queries DRY.

  4. Challenge: Build a complete GraphQL API client for a React frontend. Create components that (1) List articles with title, author, and published date, (2) Show a single article with all fields and nested relations, (3) Provide a form to create new articles, (4) Implement search with GraphQL filters. Use Apollo Client or a simple fetch-based GraphQL client.

FAQ

Does GraphQL replace the REST API?

No, both APIs are available simultaneously. You can use REST for simple CRUD operations and GraphQL for complex nested queries, or use whichever your frontend team prefers.

Is GraphQL faster than REST?

GraphQL can be faster because clients request exactly what they need, reducing response sizes. However, nested GraphQL queries can generate more database queries than equivalent REST calls with proper population.

How does authentication work with GraphQL?

Authentication uses the same JWT token system as REST. Include the Authorization: Bearer <jwt> header in GraphQL requests. The token is validated on every request.

Can I disable GraphQL for specific content types?

Yes. In the plugin configuration, you can set shadowCRUD: true for automatic schema generation. To disable specific types, you would need to customize the schema extension or set shadowCRUD: false and define schemas manually.

How do I handle file uploads with GraphQL?

File uploads in GraphQL use multipart form data and the Upload scalar type. Strapi's GraphQL plugin supports file upload mutations. Alternatively, use the REST upload endpoint and reference the file ID in your GraphQL mutation.

Mini Project

Your task: Convert a REST API integration to GraphQL.

  1. Install the GraphQL plugin in your Strapi project.
  2. Using the GraphQL playground, write and test queries that:
    • Fetch all articles with author, tags, and category populated
    • Fetch a single article by ID with all nested relations three levels deep
    • Create a new article with relations
    • Update the category of an existing article
    • Delete a tag that is no longer needed
  3. Compare the response structure between REST and GraphQL for the same data.
  4. Create a simple HTML page that uses fetch to call the GraphQL endpoint and renders the results.

What's Next

Now that you have GraphQL set up, proceed to API Customization to learn how to add custom controllers, routes, services, and middlewares to extend Strapi's default API behavior. After that, secure your API with API Security.

Related lessons:

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro