news.ycombinator.com
GraphQL kinda sucks - Hacker News
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.
Related Pain Points8件
N+1 query problem causes excessive database calls
8Developers frequently fetch all list items then make separate database calls for each item's related data, resulting in exponential query multiplication (e.g., 21 queries instead of 2 for 20 blog posts with author data). This becomes catastrophic in production with large datasets.
Sensitive data exposure and authorization complexity
8GraphQL's unified endpoint and flexible query structure can inadvertently expose sensitive data. Without strict authentication and authorization checks at the field level, unauthorized users can query restricted information. Field-level security is complex, error-prone, and can cause entire requests to fail.
Schema evolution breaks tests and introduces silent failures
7When making schema changes to evolve the application's data handling, modifications either break tests immediately or don't, creating a worse scenario where tests no longer guarantee correctness. This requires iterative fixing of data integrity issues.
Ineffective caching due to query variability
7Traditional HTTP caching mechanisms struggle with GraphQL because each unique query variation is treated as a distinct request. Parameterized queries (e.g., different $userId values) create cache misses. Additionally, query permutations can be exploited to spam server memory with cache entries.
Query complexity and performance degradation
7GraphQL queries can become increasingly complex as projects grow, with deeply nested queries and over-fetching of fields leading to poor performance, extensive database joins, and slow execution times. Query complexity assessment is difficult and clients can crater performance without guardrails.
Unnecessary complexity overhead for small projects and simple use cases
6GraphQL adds significant complexity to projects through schema management, type system duplication, tooling, and infrastructure costs. This overhead is not justified for small projects, simple APIs, or cases where use cases are well-known and static. 90% of typical API use cases can be handled by simpler alternatives.
Lack of support for associative arrays and dynamic key structures
6GraphQL does not support map/table/dictionary return types or associative arrays keyed by dynamic values. Developers must use workarounds like custom scalars, key-value object arrays, or pre-transformed responses, adding unnecessary complexity to both schema and client logic.
Type system duplication and code-first vs schema-first friction
5Depending on the backend language and code generation approach, developers must manage two or more type systems (backend native types, GraphQL schema, generated client types). Code-first and schema-first approaches each have tradeoffs and friction points.