---
title: The Graph QL Schema
---

## Overview

The schema for your Subgraph is in the file `schema.graphql`. GraphQL schemas are defined using the GraphQL interface definition language.

> Note: If you've never written a GraphQL schema, it is recommended that you check out this primer on the GraphQL type system. Reference documentation for GraphQL schemas can be found in the [GraphQL API](/subgraphs/querying/graphql-api/) section.

### Defining Entities

Before defining entities, it is important to take a step back and think about how your data is structured and linked.

- All queries will be made against the data model defined in the Subgraph schema. As a result, the design of the Subgraph schema should be informed by the queries that your application will need to perform.
- It may be useful to imagine entities as "objects containing data", rather than as events or functions.
- You define entity types in `schema.graphql`, and Graph Node will generate top-level fields for querying single instances and collections of that entity type.
- Each type that should be an entity is required to be annotated with an `@entity` directive.
- By default, entities are mutable, meaning that mappings can load existing entities, modify them and store a new version of that entity.
  - Mutability comes at a price, so for entity types that will never be modified, such as those containing data extracted verbatim from the chain, it is recommended to mark them as immutable with `@entity(immutable: true)`.
  - If changes happen in the same block in which the entity was created, then mappings can make changes to immutable entities. Immutable entities are much faster to write and to query so they should be used whenever possible.

#### Good Example

The following `Gravatar` entity is structured around a Gravatar object and is a good example of how an entity could be defined.

```graphql
type Gravatar @entity(immutable: true) {
  id: Bytes!
  owner: Bytes
  displayName: String
  imageUrl: String
  accepted: Boolean
}
```

#### Bad Example

The following example `GravatarAccepted` and `GravatarDeclined` entities are based around events. It is not recommended to map events or function calls to entities 1:1.

```graphql
type GravatarAccepted @entity {
  id: Bytes!
  owner: Bytes
  displayName: String
  imageUrl: String
}

type GravatarDeclined @entity {
  id: Bytes!
  owner: Bytes
  displayName: String
  imageUrl: String
}
```

#### Optional and Required Fields

Entity fields can be defined as required or optional. Required fields are indicated by the `!` in the schema. If the field is a scalar field, you get an error when you try to store the entity. If the field references another entity then you get this error:

```
Null value resolved for non-null field 'name'
```

Each entity must have an `id` field, which must be of type `Bytes!` or `String!`. It is generally recommended to use `Bytes!`, unless the `id` contains human-readable text, since entities with `Bytes!` id's will be faster to write and query than those with a `String!` `id`. The `id` field serves as the primary key, and needs to be unique among all entities of the same type. For historical reasons, the type `ID!` is also accepted and is a synonym for `String!`.

For some entity types the `id` for `Bytes!` is constructed from the id's of two other entities; that is possible using `concat`, e.g., `let id = left.id.concat(right.id) ` to form the id from the id's of `left` and `right`. Similarly, to construct an id from the id of an existing entity and a counter `count`, `let id = left.id.concatI32(count)` can be used. The concatenation is guaranteed to produce unique id's as long as the length of `left` is the same for all such entities, for example, because `left.id` is an `Address`.

### Built-In Scalar Types

#### GraphQL Supported Scalars

The following scalars are supported in the GraphQL API:

| Type | Description |
| --- | --- |
| `Bytes` | Byte array, represented as a hexadecimal string. Commonly used for Ethereum hashes and addresses. |
| `String` | Scalar for `string` values. Null characters are not supported and are automatically removed. |
| `Boolean` | Scalar for `boolean` values. |
| `Int` | The GraphQL spec defines `Int` to be a signed 32-bit integer. |
| `Int8` | An 8-byte signed integer, also known as a 64-bit signed integer, can store values in the range from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. Prefer using this to represent `i64` from ethereum. |
| `BigInt` | Large integers. Used for Ethereum's `uint32`, `int64`, `uint64`, ..., `uint256` types. Note: Everything below `uint32`, such as `int32`, `uint24` or `int8` is represented as `i32`. |
| `BigDecimal` | `BigDecimal` High precision decimals represented as a significand and an exponent. The exponent range is from −6143 to +6144. Rounded to 34 significant digits. |
| `Timestamp` | It is an `i64` value in microseconds. Commonly used for `timestamp` fields for timeseries and aggregations. |

### Enums

You can also create enums within a schema. Enums have the following syntax:

```graphql
enum TokenStatus {
  OriginalOwner
  SecondOwner
  ThirdOwner
}
```

Once the enum is defined in the schema, you can use the string representation of the enum value to set an enum field on an entity. For example, you can set the `tokenStatus` to `SecondOwner` by first defining your entity and subsequently setting the field with `entity.tokenStatus = "SecondOwner"`. The example below demonstrates what the Token entity would look like with an enum field:

More detail on writing enums can be found in the [GraphQL documentation](https://graphql.org/learn/schema/).

### Entity Relationships

An entity may have a relationship to one or more other entities in your schema. These relationships may be traversed in your queries. Relationships in The Graph are unidirectional. It is possible to simulate bidirectional relationships by defining a unidirectional relationship on either "end" of the relationship.

Relationships are defined on entities just like any other field except that the type specified is that of another entity.

#### One-To-One Relationships

Define a `Transaction` entity type with an optional one-to-one relationship with a `TransactionReceipt` entity type:

```graphql
type Transaction @entity(immutable: true) {
  id: Bytes!
  transactionReceipt: TransactionReceipt
}

type TransactionReceipt @entity(immutable: true) {
  id: Bytes!
  transaction: Transaction
}
```

#### One-To-Many Relationships

Define a `TokenBalance` entity type with a required one-to-many relationship with a Token entity type:

```graphql
type Token @entity(immutable: true) {
  id: Bytes!
}

type TokenBalance @entity {
  id: Bytes!
  amount: Int!
  token: Token!
}
```

### Reverse Lookups

Reverse lookups can be defined on an entity through the `@derivedFrom` field. This creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API. Rather, it is derived from the relationship defined on the other entity. For such relationships, it rarely makes sense to store both sides of the relationship, and both indexing and query performance will be better when only one side is stored and the other is derived.

For one-to-many relationships, the relationship should always be stored on the 'one' side, and the 'many' side should always be derived. Storing the relationship this way, rather than storing an array of entities on the 'many' side, will result in dramatically better performance for both indexing and querying the Subgraph. In general, storing arrays of entities should be avoided as much as is practical.

#### Example

We can make the balances for a token accessible from the token by deriving a `tokenBalances` field:

```graphql
type Token @entity(immutable: true) {
  id: Bytes!
  tokenBalances: [TokenBalance!]! @derivedFrom(field: "token")
}

type TokenBalance @entity {
  id: Bytes!
  amount: Int!
  token: Token!
}
```

Here is an example of how to write a mapping for a Subgraph with reverse lookups:

```typescript
let token = new Token(event.address) // Create Token
token.save() // tokenBalances is derived automatically

let tokenBalance = new TokenBalance(event.address)
tokenBalance.amount = BigInt.fromI32(0)
tokenBalance.token = token.id // Reference stored here
tokenBalance.save()
```

#### Many-To-Many Relationships

For many-to-many relationships, such as users that each may belong to any number of organizations, the most straightforward, but generally not the most performant, way to model the relationship is as an array in each of the two entities involved. If the relationship is symmetric, only one side of the relationship needs to be stored and the other side can be derived.

#### Example

Define a reverse lookup from a `User` entity type to an `Organization` entity type. In the example below, this is achieved by looking up the `members` attribute from within the `Organization` entity. In queries, the `organizations` field on `User` will be resolved by finding all `Organization` entities that include the user's ID.

```graphql
type Organization @entity {
  id: Bytes!
  name: String!
  members: [User!]!
}

type User @entity {
  id: Bytes!
  name: String!
  organizations: [Organization!]! @derivedFrom(field: "members")
}
```

A more performant way to store this relationship is through a mapping table that has one entry for each `User` / `Organization` pair with a schema like

```graphql
type Organization @entity {
  id: Bytes!
  name: String!
  members: [UserOrganization!]! @derivedFrom(field: "organization")
}

type User @entity {
  id: Bytes!
  name: String!
  organizations: [UserOrganization!] @derivedFrom(field: "user")
}

type UserOrganization @entity {
  id: Bytes! # Set to `user.id.concat(organization.id)`
  user: User!
  organization: Organization!
}
```

This approach requires that queries descend into one additional level to retrieve, for example, the organizations for users:

```graphql
query usersWithOrganizations {
  users {
    organizations {
      # this is a UserOrganization entity
      organization {
        name
      }
    }
  }
}
```

This more elaborate way of storing many-to-many relationships will result in less data stored for the Subgraph, and therefore to a Subgraph that is often dramatically faster to index and to query.

### Adding comments to the schema

As per GraphQL spec, comments can be added above schema entity attributes using the hash symbol `#`. This is illustrated in the example below:

```graphql
type MyFirstEntity @entity {
  # unique identifier and primary key of the entity
  id: Bytes!
  address: Bytes!
}
```

## Defining Fulltext Search Fields

Fulltext search queries filter and rank entities based on a text search input. Fulltext queries are able to return matches for similar words by processing the query text input into stems before comparing them to the indexed text data.

A fulltext query definition includes the query name, the language dictionary used to process the text fields, the ranking algorithm used to order the results, and the fields included in the search. Each fulltext query may span multiple fields, but all included fields must be from a single entity type.

To add a fulltext query, include a `_Schema_` type with a fulltext directive in the GraphQL schema.

```graphql
type _Schema_
  @fulltext(
    name: "bandSearch"
    language: en
    algorithm: rank
    include: [{ entity: "Band", fields: [{ name: "name" }, { name: "description" }, { name: "bio" }] }]
  )

type Band @entity {
  id: Bytes!
  name: String!
  description: String!
  bio: String
  wallet: Address
  labels: [Label!]!
  discography: [Album!]!
  members: [Musician!]!
}
```

The example `bandSearch` field can be used in queries to filter `Band` entities based on the text documents in the `name`, `description`, and `bio` fields. Jump to [GraphQL API - Queries](/subgraphs/querying/graphql-api/#queries) for a description of the fulltext search API and more example usage.

```graphql
query {
  bandSearch(text: "breaks & electro & detroit") {
    id
    name
    description
    wallet
  }
}
```

> **[Feature Management](#experimental-features):** From `specVersion` `0.0.4` and onwards, `fullTextSearch` must be declared under the `features` section in the Subgraph manifest.

## Languages supported

Choosing a different language will have a definitive, though sometimes subtle, effect on the fulltext search API. Fields covered by a fulltext query field are examined in the context of the chosen language, so the lexemes produced by analysis and search queries vary from language to language. For example: when using the supported Turkish dictionary "token" is stemmed to "toke" while, of course, the English dictionary will stem it to "token".

Supported language dictionaries:

| Code   | Dictionary |
| ------ | ---------- |
| simple | General    |
| da     | Danish     |
| nl     | Dutch      |
| en     | English    |
| fi     | Finnish    |
| fr     | French     |
| de     | German     |
| hu     | Hungarian  |
| it     | Italian    |
| no     | Norwegian  |
| pt     | Portuguese |
| ro     | Romanian   |
| ru     | Russian    |
| es     | Spanish    |
| sv     | Swedish    |
| tr     | Turkish    |

### Ranking Algorithms

Supported algorithms for ordering results:

| Algorithm     | Description                                                             |
| ------------- | ----------------------------------------------------------------------- |
| rank          | Use the match quality (0-1) of the fulltext query to order the results. |
| proximityRank | Similar to rank but also includes the proximity of the matches.         |
