# GraphQL APIs in .NET: When It's Worth the Complexity

GraphQL gets pitched as a universal upgrade over REST, and I don't buy that framing. I've built both REST and GraphQL APIs in production, and the honest answer is that GraphQL solves specific problems well and introduces its own complexity in exchange. Knowing which situation you're in matters more than picking a side.

### The problem GraphQL actually solves

REST endpoints are shaped around the server's idea of a resource. A mobile client that only needs a customer's name and policy status still has to hit `/customers/{id}` and get back the entire customer object, or you end up building a growing collection of purpose-built endpoints to avoid over-fetching. GraphQL flips that: the client asks for exactly the fields it needs, in one request, even when that data spans what would be several REST resources.

graphql

```graphql
query {
  customer(id: "123") {
    name
    policies {
      status
      premium
    }
  }
}
```

One round trip, exactly the fields requested, no more and no less. On mobile-heavy platforms, especially on unreliable connections, that reduction in round trips is a real, measurable improvement, not a theoretical one.

### Setting it up in .NET

HotChocolate is the library I reach for. It integrates cleanly with [ASP.NET](http://ASP.NET) Core and EF Core:

csharp

```csharp
builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .AddMutationType<Mutation>()
    .AddProjections()
    .AddFiltering()
    .AddSorting();
```

`AddProjections()` is worth calling out specifically. It translates the fields a client actually requested into the underlying EF Core query, so you're not fetching entire entities from the database just to discard most of the fields before returning them. Skip this and you lose a big part of GraphQL's efficiency advantage before it even reaches the client.

### The N+1 problem doesn't go away, it just moves

This is the part that catches teams off guard. A GraphQL query resolving nested fields can trigger a separate database call per item in a list, the same N+1 problem that plagues naive EF Core code, just expressed through resolvers instead of loops.

csharp

```csharp
public async Task<IEnumerable<Policy>> GetPoliciesAsync(
    [Parent] Customer customer, IPolicyDataLoader dataLoader)
{
    return await dataLoader.LoadAsync(customer.Id);
}
```

DataLoader batches these individual lookups into a single query, similar in spirit to `.Include()` in EF Core, but you have to deliberately wire it up. It doesn't happen automatically just because you chose GraphQL.

### Where GraphQL adds cost, not just capability

A single, flexible endpoint means you lose the simple caching that comes naturally with REST's stable URLs. Every GraphQL query is a POST to the same endpoint with a different body, so HTTP-level caching by URL is off the table. You need application-level caching strategy instead, which is more work to get right.

Rate limiting also gets harder. A REST API can reasonably say "100 requests per minute per endpoint." A GraphQL API has to reason about query complexity, because a single request asking for five levels of nested relationships can be more expensive than a hundred simple REST calls combined.

### My honest rule of thumb

For internal APIs with a small number of known consumers, REST is usually simpler and I default to it. For public or partner-facing APIs where consumers have genuinely different data needs, or for mobile clients where every round trip has a real cost, GraphQL earns its complexity. I don't reach for it because it's newer. I reach for it when the fetching problem it solves is actually the problem I have.
