Most APIs speak REST. But a growing number — GitHub, Shopify, Contentful, Hasura, your own Postgres-backed backend — speak GraphQL. If you need to query those from n8n, the built-in GraphQL node handles it natively without writing custom HTTP requests or juggling headers by hand.
This guide covers everything: how the node works, how to run queries and mutations, how to pass variables, and a free workflow JSON you can import today.
What is the n8n GraphQL Node?
The GraphQL node in n8n lets you:
- Send queries (read data) and mutations (write/update data) to any GraphQL endpoint
- Pass variables dynamically from earlier workflow nodes
- Authenticate with Header Auth, OAuth2, or API Key credentials
- Return structured JSON you can pipe into the rest of your workflow
Under the hood it sends a POST request with { query, variables } — but you write clean GraphQL syntax instead of wrestling with raw JSON bodies.
When to Use It vs. the HTTP Request Node
| Use GraphQL node | Use HTTP Request node |
|---|---|
| The endpoint is a real GraphQL API | The endpoint is REST |
| You want to write clean query syntax | You need full control over request body |
| You need variable interpolation | You're posting arbitrary JSON |
| You want built-in auth credential types | You need multipart/form-data uploads |
For genuine GraphQL APIs, the dedicated node is cleaner and less error-prone.
Basic Setup
1. Add the GraphQL Node
In your workflow canvas, click +, search for GraphQL, and add it.
2. Configure the Endpoint
Set URL to the GraphQL endpoint. For example:
- GitHub:
https://api.github.com/graphql - Shopify:
https://your-store.myshopify.com/api/2024-01/graphql.json - Your Hasura:
https://your-hasura-instance.com/v1/graphql
3. Choose Authentication
GraphQL endpoints typically use one of:
-
Header Auth — pass
Authorization: Bearer YOUR_TOKEN -
API Key — header-based key (e.g.
x-hasura-admin-secret) - OAuth2 — for services like Shopify or HubSpot
Create the credential in n8n (Settings → Credentials → New) and select it in the node.
4. Write Your Query
In the Query field, paste your GraphQL query:
query GetUser($login: String!) {
user(login: $login) {
name
email
bio
followers {
totalCount
}
}
}
5. Pass Variables
In Variables, add a JSON object:
{
"login": "{{ $json.github_username }}"
}
n8n evaluates the expression at runtime, so you can pull values from any previous node.
Running a Mutation
Mutations work exactly the same way — just write mutation syntax:
mutation CreateIssue($repoId: ID!, $title: String!, $body: String!) {
createIssue(input: { repositoryId: $repoId, title: $title, body: $body }) {
issue {
number
url
}
}
}
Variables:
{
"repoId": "{{ $json.repo_id }}",
"title": "{{ $json.issue_title }}",
"body": "{{ $json.issue_body }}"
}
The node returns the mutation result as structured JSON — pass issue.number or issue.url to downstream nodes.
Handling Pagination
GraphQL APIs often use cursor-based pagination. The pattern in n8n:
- Run first query → capture
pageInfo.endCursorandpageInfo.hasNextPage - Use an IF node to check
hasNextPage - Loop back to the GraphQL node with
after: "{{ $json.endCursor }}"in variables - Use a Merge node (Mode: Append) to collect all pages
This is cleaner than REST pagination because GraphQL pagination fields are standardized.
Real-World Use Cases
Sync GitHub Issues to Notion
Schedule Trigger → GraphQL (fetch open issues) → Loop → Notion (create/update page)
Query:
query GetIssues($owner: String!, $repo: String!, $after: String) {
repository(owner: $owner, name: $repo) {
issues(first: 50, states: OPEN, after: $after) {
nodes {
number
title
body
createdAt
labels(first: 5) { nodes { name } }
}
pageInfo { endCursor hasNextPage }
}
}
}
Query Shopify Orders
Webhook → GraphQL (fetch order details) → Google Sheets (log row)
query GetOrder($id: ID!) {
order(id: $id) {
name
email
totalPriceSet { shopMoney { amount } }
lineItems(first: 10) {
nodes { title quantity }
}
}
}
Hasura Real-time Insert
Webhook → GraphQL mutation (insert_users_one) → Slack notification
Error Handling Tips
GraphQL errors are returned in the response body with errors[], not via HTTP status codes (the status is usually 200 even when there's an error). To catch them:
- After the GraphQL node, add an IF node
- Condition:
{{ $json.errors }}→exists - True branch → Error notification
- False branch → Continue workflow
Alternatively, enable Error Workflow in workflow settings to catch unhandled failures globally.
Free Workflow JSON
Here's a working workflow that queries the GitHub GraphQL API for a user's profile and logs it to Google Sheets:
{
"name": "GraphQL – GitHub User to Sheets",
"nodes": [
{
"parameters": { "rule": { "interval": [{ "field": "hours", "hoursInterval": 24 }] } },
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [240, 300]
},
{
"parameters": {
"requestMethod": "POST",
"endpoint": "https://api.github.com/graphql",
"authentication": "headerAuth",
"query": "query GetUser($login: String!) { user(login: $login) { name email bio followers { totalCount } repositories { totalCount } } }",
"variables": "{ \"login\": \"octocat\" }",
"options": {}
},
"name": "GitHub GraphQL",
"type": "n8n-nodes-base.graphql",
"typeVersion": 1,
"position": [460, 300]
},
{
"parameters": {
"operation": "append",
"documentId": { "__rl": true, "mode": "id", "value": "YOUR_SHEET_ID" },
"sheetName": { "__rl": true, "mode": "name", "value": "Sheet1" },
"columns": {
"mappingMode": "defineBelow",
"value": {
"name": "={{ $json.data.user.name }}",
"email": "={{ $json.data.user.email }}",
"bio": "={{ $json.data.user.bio }}",
"followers": "={{ $json.data.user.followers.totalCount }}",
"repos": "={{ $json.data.user.repositories.totalCount }}"
}
}
},
"name": "Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [680, 300]
}
],
"connections": {
"Schedule Trigger": { "main": [[{ "node": "GitHub GraphQL", "type": "main", "index": 0 }]] },
"GitHub GraphQL": { "main": [[{ "node": "Google Sheets", "type": "main", "index": 0 }]] }
}
}
Import via n8n → Workflows → Import from clipboard. Replace YOUR_SHEET_ID and add your GitHub token credential.
Pro Tips
-
Introspect the schema: Most GraphQL APIs expose
/__graphqlor a playground. Use it to explore available queries/fields before building your workflow. - Batch with aliases: GraphQL lets you run multiple queries in one request using aliases — one node call, multiple results.
- Cache tokens: Store OAuth tokens in n8n credentials, not in node parameters — they'll be refreshed automatically.
-
Watch for N+1: If you're looping over items and querying GraphQL per-item, consider batching with
ids: []arguments instead.
Want More Pre-Built Workflows?
If you're building serious automations, the n8n Workflow Starter Pack ($29) includes 10 production-ready workflow JSONs with documentation — covering webhooks, Slack alerts, Stripe receipts, CRM sync, and more.
No fluff, just drop-in JSONs you can adapt in minutes.
What GraphQL APIs are you querying from n8n? GitHub, Shopify, Hasura, something custom? Drop it in the comments — happy to help debug queries.
Top comments (1)
What GraphQL APIs are you connecting to with n8n? GitHub, Shopify, Hasura, or something custom? Would love to hear what queries people are running in their workflows.