Arguments Let You Parameterize Any Field
Any field in a GraphQL schema, not just top-level query fields, can declare arguments the way a function declares parameters. A field like user(id: ID!) or posts(limit: Int, status: PostStatus) uses those arguments inside its resolver to decide exactly which data to fetch or filter, so the schema author controls precisely what each field can be parameterized by, and the client supplies concrete values inline in the query.
Cricket analogy: A field like playerStats(matchType: ODI) works like asking a stats engine for a specific player's One Day International numbers only, the way Cricinfo's Statsguru lets you filter Virat Kohli's record down to a single format instead of his whole career.
Variables Decouple Queries from Hard-Coded Values
Instead of hard-coding argument values directly into the query string, you declare named variables (prefixed with $) in the operation signature and reference them inside the selection set; the actual values are then supplied as a separate JSON object sent alongside the query in the request body. This means the query document itself never changes between requests — only the variables object does — which is essential for any client that runs the same query repeatedly with different inputs, such as a search box or a paginated list.
Cricket analogy: It's like a scoring app having one fixed template query GetPlayerStats($playerId: ID!) that stays identical every time, only swapping which player's ID gets passed in, the way a broadcast graphics template reuses the same layout for whichever batter is currently on strike.
Variable Types, Defaults, and Nullability
Each declared variable must have an explicit type in the operation signature, using the same type syntax as the schema: a bare type like String is nullable and optional, while an exclamation mark such as String! makes it non-null and required unless a default value is supplied with an equals sign, for example $limit: Int = 10. If a client sends null or omits a value for a non-null variable with no default, the server rejects the request during validation, before any resolver runs, which catches malformed requests early rather than letting them fail deep inside business logic.
Cricket analogy: Declaring $playerId: ID! is like a scorecard app refusing to even start rendering if no player is selected, catching the mistake immediately, the way a broadcast system errors out before air rather than showing a blank name mid-match.
query GetUserPosts($userId: ID!, $limit: Int = 10, $status: PostStatus) {
user(id: $userId) {
name
posts(limit: $limit, status: $status) {
id
title
publishedAt
}
}
}
# Variables sent separately in the request body:
# {
# "userId": "u_9001",
# "status": "PUBLISHED"
# }Variables are transmitted as a separate JSON object alongside the query string in the POST body, typically under a "variables" key. This separation is exactly what makes the query string itself static and reusable — a client library like Apollo Client or Relay can cache and hash the query text once and simply swap variables per request.
Why Variables Matter for Caching and Security
Because the query text stays identical across calls, servers and CDNs can implement persisted queries — storing a hash of each known query so clients send only the hash plus variables, dramatically reducing request payload size and enabling automatic query allow-listing for security. Interpolating raw values directly into a query string instead of using variables reintroduces the same class of injection risk that parameterized SQL queries were invented to prevent, since a malicious or malformed string could alter the query's structure rather than just its data.
Cricket analogy: Using variables is like a stadium's ticketing API only ever accepting a fixed 'buy ticket' query hash plus a seat-number variable, rather than accepting raw freeform query text that a scalper could tamper with to grab unauthorized seats.
If you forget the non-null marker on a variable that your resolver logic actually requires — declaring $userId: ID instead of $userId: ID! — a client can send null, and the request will pass validation but then fail deep inside a resolver, or worse, silently return an empty or wrong result instead of a clear, early validation error.
- Any field can declare arguments, defined per-field in the schema, similar to function parameters.
- Variables ($name) let you keep the query text static and reusable while only the values change per request.
- Variable types must be declared explicitly and can be non-null (Type!) or have a default value (Type = default).
- Non-null variables without defaults are validated before execution, catching missing input early.
- Static query text enables persisted queries, reducing payload size and enabling security allow-listing.
- Never string-interpolate raw values into a query — always use variables to avoid injection-style risks.
Practice what you learned
1. What is the correct syntax to declare a required (non-nullable) variable of type ID in an operation signature?
2. Why do GraphQL clients prefer variables over interpolating values directly into the query string?
3. If a variable is declared as $limit: Int = 10, what happens if the client omits it entirely?
4. At what point does GraphQL reject a request that omits a required non-null variable with no default?
Was this page helpful?
You May Also Like
Writing Queries
Learn how to construct GraphQL queries that ask a single endpoint for exactly the fields you need, nested through the schema graph.
Input Types
Learn how GraphQL input object types bundle structured arguments together, especially for mutations, and how they differ from regular object types.
Aliases and Fragments
Learn how aliases let you request the same field multiple times with different arguments, and how fragments keep repeated selection sets DRY.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics