Sources

453 sources collected

purelogics.com

Use Cases for GraphQL

### Cons GraphQL can be harder to set up; its other disadvantages are below. - **Complexity in Caching**: Traditional caching mechanisms, like HTTP caching, are not as effective with GraphQL because of its dynamic queries. It often requires custom strategies like persisted queries and Apollo Client caching. - **Increased Server Load**: Due to the complexity of GraphQL queries, server performance can sometimes suffer. It’s essential to implement rate limiting and query depth control to avoid overload. - **Learning Curve**: Developers need to familiarize themselves with schema definitions, resolvers, and query structures, making it more challenging to learn than REST APIs. Debugging can also be more complex. - **Security Risks**: There’s the potential for clients to send expensive or deeply nested queries, risking denial-of-service (DoS) attacks. Proper query validation and authorization are crucial.

5/22/2025Updated 2/23/2026

When working with complex data operations, complications often arise. These hurdles can lead to significant delays and frustration. As technologies evolve, so do the intricacies of efficiently managing data interactions. Sometimes, even minor oversights can result in considerable setbacks in development timelines. It's essential to recognize the typical pitfalls encountered during these processes. Developers frequently grapple with validation errors, performance setbacks, and unintended data retrieval issues. Such challenges are not just nuisances; they can hinder project progress and affect overall system performance. … One frequent headache is handling variable types and their mismatches. For instance, a numeric variable mistakenly passed as a string can result in runtime errors. Additionally, the lack of proper validation on input data can lead to security vulnerabilities, allowing malicious users to exploit the system. Another prevalent concern is the efficiency of data retrieval. Developers may unintentionally request excessive data, resulting in performance degradation. On the contrary, requesting too little data can lead to multiple round trips to the server, further impacting application speed and responsiveness. … One major element to consider is the depth of nested queries. When queries are deep, the system might struggle to retrieve all necessary data in a timely manner. Additionally, requests that involve multiple related entities can significantly increase the load time. Developers need to strike a balance between the richness of the data and the speed of retrieval. … Yo, one common issue I see with GraphQL is not handling errors properly. Like, some devs forget to check for errors in their resolvers and end up returning null values instead of throwing an error. Remember to always throw an error when something goes wrong, so the client knows something's up. Bro, another issue is not optimizing queries. Some peeps make the mistake of fetching more data than needed, which can slow down the server and waste resources. Make sure to only request the data that's necessary for the client and avoid over-fetching. … So, I've seen some devs struggle with handling complex data structures in GraphQL. It can be a pain to map nested objects and arrays, especially when dealing with relations between types. Take your time to plan out your schema and resolvers properly to avoid headaches later on. Aight, a common pitfall is forgetting to properly handle authentication and authorization in GraphQL. Don't just trust that the client will always send valid credentials - make sure to authenticate and authorize requests on the server side to protect your data and APIs. Sup, peeps often forget to batch their queries in GraphQL, resulting in N+1 query problems. This can lead to slow performance and put unnecessary strain on your database. Use DataLoader or other batching techniques to optimize your queries and fetch data more efficiently. One issue that devs face is dealing with schema changes in GraphQL. If you're constantly updating your schema, it can be a pain to keep everything in sync. Consider using a tool like Apollo's schema stitching or schema delegation to manage schema evolution smoothly.

2/23/2025Updated 10/29/2025

Similar to other API specifications, GraphQL should be paired with API management software to get the most benefits. GraphQL is often implemented as a gateway or middleware for different data sources, which means that the API performance and security depend on these downstream sources. To optimize GraphQL API performance, you should make use of a query cost analysis to implement rate limiting based on the connected data sources. Presentations at GraphQLConf discussed how observability and rate limiting play important roles in API management for GraphQL. ## 3. GraphQL security Security for GraphQL APIs is becoming even more critical now that enterprises have started running GraphQL at scale. As the structure of GraphQL is different from other API specifications, it has its own needs in terms of security. During the conference, GraphQL-specific vulnerabilities like complexity issues and schema leaks were highlighted. Of course, security threats that apply to standard API specifications—such as injections and server errors—also apply to GraphQL APIs and can often be mitigated by API management solutions.

10/4/2023Updated 2/25/2026

bessey.dev

Performance

### Authorisation I think this is the most widely understood risk of GraphQL, so I won’t go into too much depth here. TLDR: if you expose a fully self documenting query API to all clients, you better be damn sure that **every field** is authorised against the current user appropriately to the context in which that field is being fetched. Initially authorising **objects** seems like enough, but this quickly becomes insufficient. For example, say we are the ~~Twitter~~ X 🙄 API: … This is not a unique problem to GraphQL, and actually the strict GraphQL resolution algorithm has allowed most libraries to share a common solution: the Dataloader pattern. Unique to GraphQL though is the fact that since it is a query language, this can **become** a problem with no backend changes when a client modifies a query. As a result, I found you end up having to defensively introduce the Dataloader abstraction everywhere *just in case* a client ends up fetching a field in a list context in the future. This is a lot of boilerplate to write and maintain. … ``` class UserType < GraphQL::BaseObject field :handle, String field :birthday, authorize_with: :view_pii end class UserPolicy < ApplicationPolicy def view_pii? # Oh no, I hit the DB to fetch the user's friends user.friends_with?(record) end end ``` … This is actually trickier to deal with than our previous example, because authorisation code is not always run in a GraphQL context. It may for example be run in a background job or an HTML endpoint. That means we can’t just reach for a Dataloader naively, because Dataloaders expect to be run from within GraphQL (in the Ruby implementation anyway). … - GraphQL discourages breaking changes and provides no tools to deal with them. This adds needless complexity for those who control all their clients, who will have to find workarounds. - Reliance on HTTP response codes turns up everywhere in tooling, so dealing with the fact that 200 can mean everything from everything is Ok through to everything is down can be quite annoying.

5/24/2024Updated 3/19/2026

In the 2022 state of GraphQL study, we uncovered that Security is one of the top pain points developers face when using GraphQL. The number one pain point being error handling has caused many GraphQL APIs to leak sensitive information. Analyzing error messages is actually how our tool Graphw00f allows hackers to fingerprint your GraphQL APIs and uncover vulnerabilities.

12/11/2023Updated 10/8/2025

but beginner to mid level developers are lead down the path of USE GRAPHQL especially on youtube... and this is just unfair and wrong. The good: - It makes working with describing the data you want easy - It can save you bandwidth. Get what you ask for and no more - It makes documentation for data consumers easy - It can make subscription easier for you to use - Can let you federate API calls The bad - It is actually a pain to use, depending on the backend you are using you'll have to manage two or more type systems if there are no code first generates in your language - It doesn't support map/tables/dictionaries. This is actually huge. I get that there might be some pattern where you don't want to allow this but for the majority of situations working with json api's you'll end up with a {[key: string] : T} somewhere … please any senior dev's drop your wise words so that any new dev's can avoid tarpits ... The more fine-grained nature of boring REST calls makes it more easy to control client impact on the system. If you want to see the kind of work you actually need to put in to make a graphql API, look at Shopify. They have rate limits based on quantity of data returned. Cursors and pagination. The schema is a huge ugly mess with extra layers that never show up in the pretty examples of GraphQL on the internet. … Not saying people should use GraphQL for everything though. It’s kind of overkill for a lot of apps. PragmaticPulp on Aug 7, 2022 I worked with a team that was going down a similar path. At some point it felt like they were reinventing REST on top of GraphQL with a strict set of predefined queries and result shapes. … ryanbrunner on Aug 6, 2022 GraphQL falls into the same trap that a lot of things do IMO - it assumes that because 5% of things are complex, that you need a solution that can deal with that complexity for 100% of your API, which needlessly complicates everything else. … - Front end devs save time by.... sharing queries. So component B ends up fetching records it has no use for because its sharing GQL with component A. - Backenders never optimise column selection. You may think you are really optimising by sending a GQL query for one column, but the backend will go ahead and collect ALL the columns and then "filter" down the data that was asked for. - Backenders can also forget to handle denormalisation. If you query related many to many records but the GQL only asks for related ids of implementations will go ahead and do a full join instead of just returning results from the bridge table. - Frontenders aren't even aware you can send multiple graphql GraphL requests simultaneously. … Compare it to a database, what if you couldn't use random queries with SQL, but only had the option to call stored procedures? The problem is when genericity diffuses its way into a large system it becomes impossible to maintain. How do you refactor a code base when everything everywhere is just SQL queries. If you want to change the schema how do you know you're not breaking anything? The short answer is you don't and so the software becomes incredibly brittle. The common workaround is testing but you can never test everything and now your tests also become coupled to everything else making things even more difficult to change. … For example, field-level security pretty much means every field could be null at any time. Depending on your graphql server implementation, this might cause an entire request to fail rather than just that field to be omitted, unless you change your schema to where everything is nullable. Checking every field can also easily lead to performance issues, because it’s not uncommon for a large, complex graphql request to have hundreds or thousands of fields (particularly when displaying lists of data to a user). … The limitations of the query language make code size explode the moment you step outside simple toy examples. It doesn't have any concept of a JOIN, or of the actual relationships between your types (graphql has no concept that me == me.parent.child). You end up writing data loaders for every type so that loops in your schema can be resolved efficiently. … - Makes caching more challenging since there are now more possible permutations of the data depending on what query the client uses. A hacker could just spam your server's memory with cache entries by crafting many variations of queries. - Makes access control a lot more complicated, slower and error-prone since the query needs to be analyzed in order to determine which resources are involved in any specific query in order for the server to decide whether to allow or block access to a resource. It's not like in REST where the request tells you exactly and precisely what resource the client wants to access.

8/6/2022Updated 10/1/2025

1. **Versioning is a lie** – No clean way to retire old fields without breaking clients. 2. **Relational mapping breaks down** – N+1 queries everywhere unless you hand-optimize. 3. **Pagination is inconsistent** – Multi-dimensional trees, different needs at different levels, no standard pattern. 4. **Deep queries go unchecked** – Clients can crater performance without guardrails. 5. **Filtering gets messy** – Complex filters require awkward nested input types, often forcing you to restructure your whole query. 6. **Repeated nodes + inconsistent shapes** – No normalization, tons of duplication, and brittle client logic. 7. **Backend logic is hidden** – Seemingly “cheap” fields might hit expensive services or timeouts. 8. **Federation = Fragile** – Stitching systems across domains is complex, slow, and hard to secure. 9. **Rigid structures** – Can’t return associative data, groupings, or CTE-style responses without workarounds. … What was once sold as a lean, client-customizable API becomes a fragile dance: every component defines its own ad hoc query shape, even when 90% of those queries are identical across the app. Instead of encouraging reuse and consistency, GraphQL enables a kind of **fragmented chaos**, where the same resource is requested in a dozen ever so slightly different structures by different consumers. … So instead of saving effort, GraphQL often forces developers to **reinvent the schema at the point of use**—adding mental overhead, duplication, and inconsistency across teams. And when it comes time to refactor? Good luck—because every query is shaped differently, there’s no unified contract to update. What started as elegance has, in many cases, devolved into a structural free-for-all. … Combine this with the fact that AND/OR logic, range filters, fuzzy matches, and custom operators all require bespoke design, and your filter inputs balloon in complexity. You end up duplicating logic across `UserFilterInput`, `OrderFilterInput`, `GroupFilterInput`, etc., with no cross-schema reuse unless you manually abstract it. It’s verbose, inconsistent, and hard to test. And unless you’re building your schema on top of a query builder library (like Prisma or Hasura), **you’re hand-authoring most of it anyway—and debugging it when it goes wrong**. ... GraphQL is often praised for its flexibility—but that flexibility only goes one way: the client gets to shape the query, but the back-end must rigidly conform to the types, fields, and structures defined in the schema. And as soon as your data doesn’t neatly fit into GraphQL’s strict trees of objects and lists, you start running into walls that are surprisingly hard to get around. Take a common scenario: You want to return a collection of results, but you want them keyed by a meaningful identifier—something like an object in PHP or a dictionary in Python or JavaScript. GraphQL doesn’t support that. If you try to return an associative array or a map-like object keyed by IDs, GraphQL’s schema validation will reject it unless you wrap it in a custom scalar or convert it into an array of key/value objects—adding **unnecessary complexity** to both the schema and the client logic. You can alias fields, but you can’t change the structure of a list to suit your data modeling needs. You also can’t express “dynamic keys” cleanly. If your data comes in keyed by dynamic values—like locales, timestamps, user IDs, or anything non-static—you’re forced to hack around it with custom types, nested lists, or pre-transformed responses. The end result is awkward and repetitive. Instead of letting the structure adapt to your data, you’re stuck bending your data to fit the rigid schema. And once you do that, you’ve already **sacrificed both readability and usability** for the sake of staying schema-compliant. … And again, this isn’t just a back-end annoyance—it bleeds into the client. Developers often expect the shape of the data to match their component needs. But since GraphQL only deals in nested objects and flat arrays, they frequently have to **reshape the response manually**, writing post-processing logic just to turn lists into dictionaries, flatten hierarchies, or collapse duplicates. You’re duplicating work that a database or ORM would have done for you—except now you’re doing it on the client, every time. … > The biggest issue is the false sense of completeness The biggest issue isn’t even the technical limitations—it’s the **false sense of completeness**. GraphQL solves the surface problems. Over-fetching, under-fetching, rigid endpoints? Fixed. But behind that are deeper concerns: inconsistent pagination, broken filtering, leaky abstractions, performance bottlenecks, deeply nested N+1 bombs, unpredictable back-end behavior, rigid schema structures, federation chaos, and client-side cartwheels just to shape the data how you actually need it.

8/30/2025Updated 9/12/2025

## Why developers moved on from GraphQL to different solutions in 2024 ### GraphQL seems to be too complex for small projects My impression is that there's the general sentiment that GraphQL is too complex for small projects. Indeed, GraphQL adds complexity to your project, but this complexity also comes with some benefits. GraphQL forces you to have a Schema, either by defining it upfront (schema-first) or by deriving it from your code (code-first). But a Schema also gives you a lot of benefits, like being able to generate types for your frontend, and being able to generate documentation. It's worth noting that there's a lot of ongoing investment in making it easier to build GraphQL APIs. ... Now let's take a look at some considerations you have to make when rate limiting a GraphQL API. - You can rate limit based on the complexity of the query (depth, number of fields, etc.) - You can rate limit based on the number of Subgraph requests - You can rate limit based on the actual load on your origin server (but how do you measure that?) - How will a user know how much they can request? How can they estimate the cost of their query? - How can a client automatically back off when they're rate limited? … ### GraphQL creates a lot of security concerns GraphQL does indeed require you to think about security in a different way than REST. GraphQL inherits all security concerns from HTTP-based APIs like REST, and then adds some more on top of that because of the flexibility of the query language. As with rate limiting and caching, the GraphQL ecosystem is very mature and has solutions for security as well, but you can see that there's a theme here: A query-style API is fundamentally different from a URL-based API. The "Q" in GraphQL gives you a lot of power, and that comes at a cost. … ### Using GraphQL leads to unnecessary complexity I have empathy for this tweet. You use a technology that adds complexity to your project, and over time, it turns into a complete mess. We all have been there. What I've learned is that it's usually not the technology that's at fault, but the way we use it. You can mess up the architecture of a REST API just as much as you can mess up the architecture of a GraphQL API. When a team is incapable of building a good REST API, and then migrates to GraphQL, it'll surprise me if they suddenly build a good GraphQL API. … ### GraphQL makes projects slower, more complex, and more likely to fail This tweet carries a slightly negative sentiment, but we can take a look at the points made and see if they are valid. First, I think it's generally wrong to say that GraphQL makes projects slower, more complex, and more likely to fail. This is a very broad statement that's lacking specifics and is hard to prove. It goes on to say that 90% of GraphQL use cases can be handled by using a simple REST API. Why only 90%? There's almost no use case that you cannot model with REST. Lastly, it says that GraphQL is overused by engineers who prioritize their well-being over user value and time to market. I don't actually see this as criticism of GraphQL, but rather as criticism of engineers who prioritize their personal goals, e.g. using a technology they like, over the goals of the company. The last point is valid for any technology, not just GraphQL. We write software to solve problems for our users/customers (hopefully), not just to use the latest and greatest technology. That said, Engineers are also humans and want to enjoy their work. I think it's fine to use a technology that you enjoy as long as it doesn't hurt the company. … - GraphQL seems to be too complex for small projects - Rate limiting GraphQL APIs seems to be hard - Small teams don't benefit from the upsides of GraphQL - REST gets the job done - GraphQL doesn't play nice with the Web - GraphQL creates a lot of security concerns - You can just build a custom Endpoint for that - You don't need GraphQL when all use cases are known - Using GraphQL leads to unnecessary complexity - Server Actions, TypeScript and a Cache are all you need - GraphQL makes projects slower, more complex, and more likely to fail We can condense these reasons into one sentence: > GraphQL is too much overhead, and there are simpler alternatives like REST and RPC.

3/12/2024Updated 3/27/2026

I thought this was really smart. Having a JSON Schema for every operation would allow us to easily generate clients, forms, and documentation. However, as time went on, I realized that this approach is not as practical as I initially thought. Most companies had adopted existing GraphQL tools and libraries, which rely on the GraphQL schema. Adding this additional JSON-RPC layer introduces complexity and unnecessary overhead. … ## Generated GraphQL APIs: Tight Coupling as a Service I said the following on generating GraphQL APIs in 2020: > - works well for small projects and prototyping > - lacks capabilities to design > - violates information hiding > - forces business logic onto API consumers > - doesn't abstract away storage > - is hard to evolve because of tight coupling … ## GraphQL's @defer and @stream Directives are overkill In February 2023, I served a sizzling side of spice: > I argued that the `@defer` and `@stream` directives are overkill. My point was that we could instead use a Backend For Frontend layer to achieve the same results with less complexity. This is, once again, a topic where I previously was in favor of a JSON-RPC layer in front of GraphQL. ... … From discussions with our customers, it's clear that latency of Subgraph responses can vary significantly depending on the underlying services. For many use cases, every millisecond counts in the battle to provide the best possible user experience. Providers of e-commerce platforms, for example, can measure the impact of a 100ms delay in the response time in terms of lost revenue. With the help of the `@defer` and `@stream` directives, it's possible to optimize critical rendering paths in a way that shows the most important data first while the rest of the data is fetched in the background.

12/3/2024Updated 3/30/2026

GraphQL didn’t go viral because devs were bored. It solved **real pain**. - **Overfetching/Underfetching**: REST gives you too much or too little. GraphQL gives you just what you asked for. - **Too Many Endpoints**: GraphQL says, "One endpoint to rule them all." - **Mobile-First**: For apps where bandwidth matters? GraphQL is lean and mean. - **Frontend Freedom**: React + GraphQL is like chai + biscuit. Tightly paired.

4/11/2025Updated 3/22/2026

## # GraphQL pain points and solutions Despite its numerous benefits, using GraphQL in production comes with several challenges. This is reflected in the 2024 GraphQL survey. These issues range from performance to security concerns, and they require thoughtful solutions to ensure that these drawbacks do not overshadow the benefits of GraphQL in enabling versatile and efficient APIs. Let’s explore them. ### Query complexity As the scope of a project grows, GraphQL queries can become increasingly complex, affecting execution time and resource consumption. In the context of GraphQL, query complexity refers to the assessment of the computational resources that a server would need to fulfill a request. The complexity of a query increases with the number of fields and the depth of the query. Assessing query complexity is important because, if high, it can lead to performance issues. Here are reasons that can cause complexity and how to overcome them: **1. Deeply nested queries:** GraphQL allows clients to use a single request for nested data in a single query. This can lead to deeply nested queries, which may result in poor performance, extensive database joins, or complex data fetching logic — increasing the execution time. For example, a complex query might request books, their authors, the author's other books, and reviews for those books; this creates a deeply nested structure: … **2. Over-fetching of fields:** One of the primary advantages of GraphQL is its ability to mitigate over-fetching, where clients receive more data than they need. Despite this, it's still possible to encounter over-fetching if the queries are not carefully constructed. Over-fetching can lead to increased processing time and slower response rates, as unnecessary data is processed and transmitted over the network. … **3. Pagination for large lists:** Queries that return large lists of data can be slow to execute, especially if each item in the list requires additional database lookups to resolve related fields. To overcome this problem, you can implement pagination using `first`, `last`, and `after` arguments. Suppose you want to fetch a list of the first ten books with pagination. The query can look like this: … ### Exposing sensitive data A single GraphQL endpoint can inadvertently expose sensitive data due to its highly flexible query structure, allowing clients to request exactly what they need. Without stringent authentication and authorization checks, an unauthorized user could potentially query sensitive information they shouldn't have access to. This risk stems from GraphQL's nature of providing a unified interface to all data, requiring careful implementation of robust authentication and authorization security measures to restrict access based on user roles and permissions. … ### Backward compatibility and schema changes Maintaining backward compatibility and managing schema changes in GraphQL can be challenging, especially as the application and its data requirements evolve. The schema defines the data structure and operations available to clients, including queries, mutations, and subscriptions. When changes are made to the schema—such as adding, renaming, or removing fields—they can have significant implications for existing clients that rely on those schema definitions. … This change breaks existing queries that expect `author` to be a string, which leads to backward compatibility issues. Schema stitching and federation are two strategies designed to handle schema evolution and distributed systems in GraphQL. They help maintain backward compatibility and extend schemas in a scalable manner for improved performance. Schema stitching allows for the merging of multiple GraphQL schemas into one. ... … However, the GraphQL ecosystem operates differently. It typically uses a single endpoint and HTTP POST method for all requests, and it returns a `200 OK` status code for most GraphQL responses, even if the query contains errors. This behavior means clients can't rely on HTTP status codes to understand what went wrong. Instead, GraphQL includes any errors in the response body alongside any data that could be retrieved. The lack of standardized error handling can make it difficult for clients to programmatically determine the nature of an error and decide how to handle it. … This response indicates that the query failed partially (trying to fetch a `user` that doesn't exist) but doesn't follow a standard error code system. The client needs to parse the error message string, which can be fragile and not standardized across different GraphQL services. Since GraphQL does not enforce a specific error-handling mechanism, developers are encouraged to implement their custom error-handling logic. This involves defining status fields, error codes, and error messages within the GraphQL schema to make error responses more predictable and useful. … Each time you change the `$userId`, the server considers it a unique query, making it hard for traditional caching mechanisms to recognize and cache the response effectively. To mitigate this, several strategies can be employed: **1. Client-side caching:** Client-side libraries like Apollo Client offer built-in caching capabilities, storing the results of queries for reuse without needing to return to the server.

12/8/2025Updated 3/30/2026

joshstrange on May 30, 2024 With most tech that I screw up I assume that "I wasn't using it right" but with GraphQL I'm not sure how anyone could. The permissions/auth aspect alone is a nightmare. Couple that with potential performance issues (N+1 or just massive amounts of data) and I want nothing to do with GraphQL anymore. Everything we attempted to fix our permissions issues just caused more problems. It would break existing queries and debugging GraphQL sucked so much. … Again, fetching and updating data is easy until you need to handle edge cases. I have the same feelings about Firebase and friends. Feels like magic at the start but falls down quick and/or becomes way too complicated. GraphQL feels like DRY run amuck, "I have to keep writing CRUD, let me abstract that away", ok but now if you need special logic for certain use-cases you have a mess on your hands. Maybe GraphQL has ways to solve it but I'll bet my hat that it's overly complicated and hard to follow, like most of GraphQL once you get past the surface. … But GraphQL has everything in it to make such problems even harder. And both these projects had clear signs of "learning-on-the-go" with loads of bad practices (especially for the N+1 problem). Issue descriptions were much vaguer, harder to find in logs and performance issues popped up in the most random places (code that had been running and untouched for ages).

5/30/2024Updated 11/26/2025