On the frontend, you have a choice to use some of the heavier libraries that support all of the features (like subscriptions) - but otherwise, you can just POST a gql query to the server and it will return a blob of json, which really isn't so much more than REST.
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.
Managing permissions is so much more of a pain compared to REST because exactly what data is returned is so much more dynamic. If you have some confidential data nested 10 layers deep in the query, you get two choices. Either fail the entire query with a NotAllowed based on one deeply nested field that the client maybe does not even care about, or you have to make your schema super loose and make every single field that's subject to permission management nullable. So much easier on a REST endpoint because the response is more constrained.
Our code size for our graphql endpoint has remained totally unchanged for the past couple of years. It took only a few files (of admittedly complex code) to automatically set it up so that it would automatically provide all models via the graphql schema (and a separate permissions implementation restricts access at each level of the schema). It updates automatically whenever we add new models or permissions. This is built on top of Rails and the graphql gem.