GraphQL Variables in Queries
Variables let you write a query once and reuse it with different values. Instead of hardcoding an ID or filter value inside the query string, you pass it separately as a variable. This is how every production GraphQL client sends data to the server.
The Problem with Hardcoded Values
Hardcoding values directly in the query string forces you to build the query string dynamically in your code. String concatenation is messy, error-prone, and opens the door to injection attacks.
✗ Hardcoded — must rebuild the string for each user:
────────────────────────────────────────────────────
const query = `{ user(id: "${userId}") { name } }`;
// Fragile: breaks if userId contains special characters
✓ With variables — query string never changes:
───────────────────────────────────────────────
const query = `
query GetUser($id: ID!) {
user(id: $id) { name }
}
`;
const variables = { id: userId };
Three Parts of a Variable Query
Part 1: Declare the variable in the operation signature
─────────────────────────────────────────────────────
query GetProduct($productId: ID!, $currency: String) {
↑ variable name ↑ variable type
Part 2: Use the variable inside the query
─────────────────────────────────────────
product(id: $productId) {
price(currency: $currency)
}
}
Part 3: Send the variable values alongside the query
──────────────────────────────────────────────────────
// Sent as JSON in the HTTP request body:
{
"query": "query GetProduct($productId: ID!, ...) { ... }",
"variables": {
"productId": "p99",
"currency": "USD"
}
}
Full Example
Schema:
────────
type Query {
employee(id: ID!): Employee
}
Query operation:
─────────────────
query GetEmployee($empId: ID!) {
employee(id: $empId) {
name
department
salary
}
}
Variables object:
──────────────────
{
"empId": "emp_312"
}
Response:
──────────
{
"data": {
"employee": {
"name": "Divya Sharma",
"department": "Engineering",
"salary": 85000
}
}
}
Variable Types Match the Argument Type
The type you declare for a variable must match the type the argument expects in the schema. If the schema expects ID!, declare the variable as $id: ID!. Mismatches cause a validation error before the query runs.
Schema argument Variable declaration Matches? ────────────── ──────────────────── ──────── id: ID! $id: ID! ✓ limit: Int $limit: Int ✓ filter: String! $filter: String ✗ (required vs optional mismatch)
Default Values for Variables
Variables can have default values. If the client does not send a value for that variable, the query uses the default.
query ListProducts($limit: Int = 10, $sort: ProductSort = NEWEST_FIRST) {
products(limit: $limit, sort: $sort) {
name
price
}
}
// Sending no variables → limit=10, sort=NEWEST_FIRST
// Sending { limit: 5 } → limit=5, sort=NEWEST_FIRST
// Sending { limit: 5, sort: PRICE_ASC } → limit=5, sort=PRICE_ASC
Using Variables with Mutations
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
createdAt
}
}
Variables:
───────────
{
"input": {
"title": "GraphQL Variables Explained",
"content": "Variables are essential for...",
"tags": ["graphql", "api"]
}
}
Key Points
- Variables separate the query structure from the data values, making queries reusable and safe.
- Declare variables in the operation signature with
$name: Type. - Use variables inside the query with
$name. - Send variable values as a separate JSON object alongside the query string in the HTTP request.
- Variable types must match the schema argument types exactly.
