# Resolvers - Hot Chocolate

> Introduction to resolvers in Hot Chocolate: how the resolver tree executes a query, defining resolver methods, accessing arguments, and injecting services.

Canonical source: https://chillicream.com/docs/hotchocolate/resolvers

Every field in a GraphQL schema is backed by a resolver function that produces the field's value. Understanding how resolvers compose into a tree is the key mental model for building efficient GraphQL APIs with Hot Chocolate.

## The Resolver Tree

When Hot Chocolate receives a query, it builds a resolver tree that mirrors the shape of the request. Consider this query:

GraphQL

```
query {
  me {
    name
    company {
      id
      name
    }
  }
}
```

This produces the following resolver tree:

The execution engine traverses this tree starting from root resolvers. A child resolver can only execute after its parent has produced a value. Sibling resolvers at the same level run in parallel. Because of this parallel execution, resolvers (except top-level mutation field resolvers) must be free of side effects.

Execution completes when every resolver in the tree has produced a result.

## Defining a Resolver

Resolvers can be defined in a way that should feel very familiar to C# developers, as they either translate to methods or delegates.

In the implementation-first approach, a public method is automatically inferred as a resolver. This means the method defines both the field in your schema and the logic to resolve its value.

C#

```
[QueryType]
public partial class Query
{
    public static string Foo() => "Bar";
}
```

This generates the following schema:

SDL

```
type Query {
  foo: String!
}
```

Resolvers do not have to be methods. Public properties are also inferred as resolvers and exposed as fields in your schema.

C#

```
[QueryType]
public partial class Query
{
    public static User User => new User("Ted");
}

public record User(string Name);
```

In this case, the property `Name` of the `User` object is also inferred as a resolver.

### Async Resolver

Resolvers can be synchronous or asynchronous. Most data fetching operations, such as calling a service or database, are asynchronous.

The most important aspect of async resolvers is to honor the CancellationToken. This allows execution to be cancelled if the client abandons the request, preventing unnecessary work and resource usage.

When using the implementation-first approach, you can add a `CancellationToken` parameter to your resolver method. The execution engine will automatically inject the request's cancellation token.

C#

```
public class Query
{
    public async Task<Product> GetProductByIdAsync(
      int id,
      ProductService productService,
      CancellationToken cancellationToken)
      => await productService.GetAsync(cancellationToken);
}
```

## Arguments

In GraphQL, fields are conceptually similar to methods in C#. Just like methods, fields can have arguments, and you can access these argument values directly in your resolvers.

When using the implementation-first approach, any parameter in your resolver method that is not a service, a `CancellationToken`, or specially annotated is treated as a GraphQL argument. The execution engine will inject the argument value from the query into these parameters. For example, in the method below, the `id` parameter is recognized as an argument, while `ProductService` is injected as a service from the DI container.

C#

```
public class Query
{
    public async Task<Product> GetProductByIdAsync(
      int id,
      ProductService productService,
      CancellationToken cancellationToken)
      => await productService.GetAsync(cancellationToken);
}
```

[Learn more about arguments](https://chillicream.com/docs/hotchocolate/defining-a-schema/arguments)

## Injecting Services

Hot Chocolate automatically recognizes types registered in the DI container and injects them into resolver parameters.

C#

```
public class Query
{
    public List<User> GetUsers(UserService userService)
        => userService.GetUsers();
}
```

While you can take attributes to annotate services, you do not have to for non-keyed services.

C#

```
public class Query
{
    public List<User> GetUsers([Service] UserService userService)
        => userService.GetUsers();
}
```

[Learn more about dependency injection](https://chillicream.com/docs/hotchocolate/resolvers/dependency-injection)

## Accessing parent values

Each field resolver has access to the value that was resolved for its parent type.

For example, consider the following schema:

SDL

```
type Query {
  me: User!;
}

type User {
  id: ID!;
  friends: [User!]!;
}
```

The `User` schema type is represented by a `User` runtime class. The `id` field is a property on this class.

C#

```
public class User
{
    public string Id { get; set; }
}
```

The `friends` resolver, by contrast, is independent: it is not declared on the `User` type and uses the user's `Id` to compute its result. From the `friends` resolver's perspective, the `User` runtime object is its _parent_.

Access the parent value like this:

In the implementation-first approach, the parent object can be injected as a resolver parameter:

C#

```
[ObjectType<User>]
public static partial class UserNode
{
    public static Task<List<User>> GetFriendsAsync(
        [Parent] User user,
        UserService userService,
        CancellationToken cancellationToken)
    {
        // Omitted code for brevity
    }
}
```

If database projections are enabled, the parent object may only contain the fields requested by the client. To ensure the projections engine also loads properties required by the resolver, declare those requirements on the parent parameter:

C#

```
[ObjectType<User>]
public static partial class UserNode
{
    public static Task<List<User>> GetFriendsAsync(
        [Parent(requires: nameof(User.Id))] User user,
        UserService userService,
        CancellationToken cancellationToken)
    {
        // Omitted code for brevity
    }
}
```

Use `nameof` to make this requirement refactoring-safe.

## What's in This Section

- [Dependency Injection](https://chillicream.com/docs/hotchocolate/resolvers/dependency-injection) explains how services are injected into resolvers, scoping behavior, keyed services, and switching the service provider.
- [Errors](https://chillicream.com/docs/hotchocolate/resolvers/errors) covers how exceptions become GraphQL errors, error filters for mapping domain exceptions, and throwing `GraphQLException` for explicit errors.
- [Field Middleware](https://chillicream.com/docs/hotchocolate/resolvers/field-middleware) shows how to build reusable middleware that runs before or after resolvers, including ordering, class-based middleware, and attribute-based middleware.
[Edit this page on GitHub](https://github.com/ChilliCream/graphql-platform/edit/main/website/content/docs/hotchocolate/resolvers/index.md)

Last updated on **July 01, 2026** by **Tobias Tengler**
