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.

Leave a Comment