---
title: Querying Best Practices
---

Use The Graph's GraphQL API to query [Subgraph](/subgraphs/overview/) data efficiently. This guide outlines essential GraphQL rules, guides, and best practices to help you write optimized, reliable queries.

---

## Querying a GraphQL API

### The Anatomy of a GraphQL Query

> GraphQL queries use the GraphQL language, which is defined in the [GraphQL specification](https://spec.graphql.org/).

Unlike REST APIs, GraphQL APIs are built on a schema-driven design that defines which queries can be performed.

Here's a typical query to fetch a `token`:

```graphql
query GetToken($id: ID!) {
  token(id: $id) {
    id
    owner
  }
}
```

which will return a predictable JSON response (when passing the proper `$id` variable value):

```json
{
  "token": {
    "id": "...",
    "owner": "..."
  }
}
```

The above `GetToken` query is composed of multiple language parts (replaced below with `[...]` placeholders):

```graphql
query [operationName]([variableName]: [variableType]) {
  [queryName]([argumentName]: [variableName]) {
    # "{ ... }" express a Selection-Set, we are querying fields from `queryName`.
    [field]
    [field]
  }
}
```

### Rules for Writing GraphQL Queries

> Important: Failing to follow these rules will result in an error from The Graph API.

1. Each `queryName` must only be used once per operation.
2. Each `field` must be used only once in a selection (you cannot query `id` twice under `token`).
3. Complex types require a selection of sub-fields.
   - For example, some `fields' or queries (like `tokens`) return complex types which will require a selection of sub-fields. Not providing a selection when expected or providing one when not expected will raise an error, such as `id`. To know a field type, please refer to [Graph Explorer](/subgraphs/existing-subgraphs/explorer/).
4. Any variable assigned to an argument must match its type.
5. Variables must be uniquely defined and used.

**For a complete list of rules with code examples, check out the GraphQL Validations guide**.

### How to Send a Query to a GraphQL API

[GraphQL is a query language](https://graphql.org/learn/) and a set of conventions for APIs, typically used over HTTP to request and send data between clients and servers. This means that you can query a GraphQL API using standard `fetch` (natively or via `@whatwg-node/fetch` or `isomorphic-fetch`).

However, as recommended in [Querying from an Application](/subgraphs/querying/from-an-application/), it's best to use `graph-client`, which supports the following unique features:

- Cross-chain Subgraph Handling: Querying from multiple Subgraphs in a single query
- [Automatic Block Tracking](https://github.com/graphprotocol/graph-client/blob/main/packages/block-tracking/README.md)
- [Automatic Pagination](https://github.com/graphprotocol/graph-client/blob/main/packages/auto-pagination/README.md)
- Fully typed result

Example query using `graph-client`:

```tsx
import { execute } from '../.graphclient'

const query = `
query GetToken($id: ID!) {
  token(id: $id) {
    id
    owner
  }
}
`
const variables = { id: '1' }

async function main() {
  const result = await execute(query, variables)
  // `result` is fully typed!
  console.log(result)
}

main()
```

For more alternatives, see ["Querying from an Application"](/subgraphs/querying/from-an-application/).

---

## Best Practices

### 1. Always Write Static Queries

A common bad practice is to dynamically build a query string as follows:

```tsx
const id = params.id
const fields = ['id', 'owner']
const query = `
query GetToken {
  token(id: ${id}) {
    ${fields.join('\n')}
  }
}
`

// Execute query...
```

While the example above produces a valid GraphQL query, it comes with several issues:

- The full query is harder to understand.
- Developers are responsible for safely sanitizing the string interpolation.
- Not sending the values of the variables as part of the request can block server-side caching.
- It prevents tools from statically analyzing the query (e.g.linters or type generation tools).

Instead, it's recommended to **always write queries as static strings**.

Example of static string:

```tsx
import { execute } from 'your-favorite-graphql-client'

const id = params.id
const query = `
query GetToken($id: ID!) {
  token(id: $id) {
    id
    owner
  }
}
`

const result = await execute(query, {
  variables: {
    id,
  },
})
```

Static strings have several **key advantages**:

- Queries are easier to read, manage, and debug.
- Variable sanitization is handled by the GraphQL server.
- Variables can be cached at the server level.
- Queries can be statically analyzed by tools (see [GraphQL Essential Tools](/subgraphs/querying/best-practices/#graphql-essential-tools-guides)).

### 2. Include Fields Conditionally in Static Queries

Including fields in static queries only for a particular condition improves performance and keeps responses lightweight by fetching only the necessary data when it's relevant.

- The `@include(if:...)` directive tells the query to **include** a specific field only if the given condition is true.
- The `@skip(if: ...)` directive tells the query to **exclude** a specific field if the given condition is true.

Example using `owner` field with `@include(if:...)` directive:

```tsx
import { execute } from 'your-favorite-graphql-client'

const id = params.id
const query = `
query GetToken($id: ID!, $includeOwner: Boolean) {
  token(id: $id) {
    id
    owner @include(if: $includeOwner)
  }
}
`

const result = await execute(query, {
  variables: {
    id,
    includeOwner: true,
  },
})
```

### 3. Ask Only For What You Want

GraphQL is known for its "Ask for what you want” tagline, which is why it requires explicitly listing each field you want. There's no built-in way to fetch all available fields automatically.

- When querying GraphQL APIs, always think of querying only the fields that will actually be used.
- Make sure queries only fetch as many entities as you actually need. By default, queries will fetch 100 entities in a collection, which is usually much more than what will actually be used, e.g., for display to the user. This applies not just to top-level collections in a query, but even more so to nested collections of entities.

For example, in the following query:

```graphql
query listTokens {
  tokens {
    # will fetch up to 100 tokens
    id
    transactions {
      # will fetch up to 100 transactions
      id
    }
  }
}
```

The response could contain 100 transactions for each of the 100 tokens.

If the application only needs 10 transactions, the query should explicitly set **`first: 10`** on the transactions field.

### 4. Use a Single Query to Request Multiple Records

By default, Subgraphs have a singular entity for one record. For multiple records, use the plural entities and filter: `where: {id_in:[X,Y,Z]}` or `where: {volume_gt:100000}`

Example of inefficient querying:

```graphql
query SingleRecord {
  entity(id: X) {
    id
    name
  }
}
query SingleRecord {
  entity(id: Y) {
    id
    name
  }
}
```

Example of optimized querying:

```graphql
query ManyRecords {
  entities(where: { id_in: [X, Y] }) {
    id
    name
  }
}
```

### 5. Combine Multiple Queries in a Single Request

Your application might require querying multiple types of data as follows:

```graphql
import { execute } from "your-favorite-graphql-client"

const tokensQuery = `
query GetTokens {
  tokens(first: 50) {
    id
    owner
  }
}
`
const countersQuery = `
query GetCounters {
  counters {
    id
    value
  }
}
`

const [tokens, counters] = Promise.all(
  [
    tokensQuery,
    countersQuery,
  ].map(execute)
)
```

While this implementation is valid, it will require two round trips with the GraphQL API.

It's best to send multiple queries in the same GraphQL request as follows:

```graphql
import { execute } from "your-favorite-graphql-client"

const query = `
query GetTokensandCounters {
  tokens(first: 50) {
    id
    owner
  }
  counters {
    id
    value
  }
}
`

const  { result: { tokens, counters } } = execute(query)
```

Sending multiple queries in the same GraphQL request **improves the overall performance** by reducing the time spent on the network (saves you a round trip to the API) and provides a **more concise implementation**.

### 6. Leverage GraphQL Fragments

A helpful feature to write GraphQL queries is GraphQL Fragment.

Looking at the following query, you will notice that some fields are repeated across multiple Selection-Sets (`{ ... }`):

```graphql
query {
  bondEvents {
    id
    newDelegate {
      id
      active
      status
    }
    oldDelegate {
      id
      active
      status
    }
  }
}
```

Such repeated fields (`id`, `active`, `status`) bring many issues:

- More extensive queries become harder to read.
- When using tools that generate TypeScript types based on queries (_more on that in the last section_), `newDelegate` and `oldDelegate` will result in two distinct inline interfaces.

An optimized version of the query would be the following:

```graphql
query {
  bondEvents {
    id
    newDelegate {
      ...DelegateItem
    }
    oldDelegate {
      ...DelegateItem
    }
  }
}

# we define a fragment (subtype) on Transcoder
# to factorize repeated fields in the query
fragment DelegateItem on Transcoder {
  id
  active
  status
}
```

Using a GraphQL `fragment` improves readability (especially at scale) and results in better TypeScript types generation.

When using the types generation tool, the above query will generate a proper `DelegateItemFragment` type (_see last "Tools" section_).

## GraphQL Fragment Guidelines

### Dos and Don'ts for Fragments

1. Fragments cannot be based on non-applicable types (types without fields).
2. `BigInt` cannot be used as a fragment's base because it's a **scalar** (native "plain" type).

Example:

```graphql
fragment MyFragment on BigInt {
  # ...
}
```

3. Fragments belong to specific types and must be used with those same types in queries.
4. Spread only fragments matching the correct type.

Example:

```graphql
query {
  bondEvents {
    id
    newDelegate {
      ...VoteItem # Error! `VoteItem` cannot be spread on `Transcoder` type
    }
    oldDelegate {
      ...VoteItem
    }
  }
}

fragment VoteItem on Vote {
  id
  voter
}
```

- `newDelegate` and `oldDelegate` are of type `Transcoder`. It's not possible to spread a fragment of type `Vote` here.

5. Fragments must be defined based on their specific usage.
6. Define fragments as an atomic business unit of data.

---

### How to Define `Fragment` as an Atomic Business Unit of Data

> For most use-cases, defining one fragment per type (in the case of repeated fields usage or type generation) is enough.

Here is a rule of thumb for using fragments:

- When fields of the same type are repeated in a query, group them in a `Fragment`.
- When similar but different fields are repeated, create multiple fragments.

Example:

```graphql
# base fragment (mostly used in listing)
fragment Voter on Vote {
  id
  voter
}

# extended fragment (when querying a detailed view of a vote)
fragment VoteWithPoll on Vote {
  id
  voter
  choiceID
  poll {
    id
    proposal
  }
}
```

---

## GraphQL Essential Tools Guides

### Test Queries with Graph Explorer

Before integrating GraphQL queries into your dapp, it's best to test them. Instead of running them directly in your app, use a web-based playground.

Start with [Graph Explorer](https://thegraph.com/explorer), a preconfigured GraphQL playground built specifically for Subgraphs. You can experiment with queries and see the structure of the data returned without writing any frontend code.

If you want alternatives to debug/test your queries, check out other similar web-based tools:

- [GraphiQL](https://graphiql-online.com/graphiql)
- [Altair](https://altairgraphql.dev/)

### Setting up Workflow and IDE Tools

In order to keep up with querying best practices and syntax rules, use the following workflow and IDE tools.

#### GraphQL ESLint

1. Install GraphQL ESLint

Use [GraphQL ESLint](https://the-guild.dev/graphql/eslint/docs/getting-started) to enforce best practices and syntax rules with zero effort.

2. Use the ["operations-recommended"](https://the-guild.dev/graphql/eslint/docs/configs) config

This will enforce essential rules such as:

- `@graphql-eslint/fields-on-correct-type`: Ensures fields match the proper type.
- `@graphql-eslint/no-unused variables`: Flags unused variables in your queries.

Result: You'll **catch errors without even testing queries** on the playground or running them in production!

#### Use IDE plugins

GraphQL plugins streamline your workflow by offering real-time feedback while you code. They highlight mistakes, suggest completions, and help you explore your schema faster.

1. VS Code

Install the [GraphQL VS Code extension](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql) to unlock:

- Syntax highlighting
- Autocomplete suggestions
- Validation against schema
- Snippets
- Go to definition for fragments and input types

If you are using `graphql-eslint`, use the [ESLint VS Code extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to visualize errors and warnings inlined in your code correctly.

2. WebStorm/Intellij and GraphQL

Install the [JS GraphQL plugin](https://plugins.jetbrains.com/plugin/8097-graphql/). It significantly improves the experience of working with GraphQL by providing:

- Syntax highlighting
- Autocomplete suggestions
- Validation against schema
- Snippets

For more information on this topic, check out the [WebStorm article](https://blog.jetbrains.com/webstorm/2019/04/featured-plugin-js-graphql/) which showcases all the plugin's main features.
