Export orders for a date range with a bulk operation
Export every Shopify order in a date range, with line items, to a JSONL file using bulkOperationRunQuery and an orders search filter.
- API
- Admin GraphQL API
- Operations
- bulkOperationRunQuery, bulkOperation
- Access scopes
- read_orders; add read_all_orders for orders older than 60 days
- Replaces (REST)
- GET /admin/api/orders.json with created_at_min and created_at_max
- API version
- 2026-10
- Last checked
In short
To export Shopify orders for a date range, pass an orders query with a created_at filter to the bulkOperationRunQuery mutation, poll the bulkOperation query until the status is COMPLETED, then download the JSONL file from url. Line items arrive as separate lines with a __parentId. Your app needs read_orders, plus read_all_orders for orders older than 60 days.
How to use it
- Write the orders query with a search filter such as created_at:>=2026-07-01 AND created_at:<2026-10-01. Put only the fields you need inside it.
- Send it as the query variable of StartOrderExport and keep the returned bulk operation ID.
- Poll OrderExportStatus every few seconds, or subscribe to the bulk_operations/finish webhook, until status is COMPLETED.
- Download the file at url and read it line by line. Attach each line item to its order with __parentId.
Code
bulk-operation-run-query.graphqlmutation StartOrderExport($query: String!) {
bulkOperationRunQuery(query: $query) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
bulk-operation-run-query.variables.json{
"query": "{ orders(query: \"created_at:>=2026-07-01 AND created_at:<2026-10-01\", sortKey: CREATED_AT) { edges { node { id name createdAt displayFinancialStatus displayFulfillmentStatus currencyCode totalPriceSet { shopMoney { amount currencyCode } } lineItems { edges { node { id sku quantity originalUnitPriceSet { shopMoney { amount } } } } } } } } }"
}
bulk-operation-run-query.response.json{
"data": {
"bulkOperationRunQuery": {
"bulkOperation": {
"id": "gid://shopify/BulkOperation/1234567890",
"status": "CREATED"
},
"userErrors": []
}
}
}
bulk-operation-status.graphqlquery OrderExportStatus($id: ID!) {
bulkOperation(id: $id) {
id
status
errorCode
objectCount
rootObjectCount
url
partialDataUrl
}
}
bulk-operation-status.variables.json{
"id": "gid://shopify/BulkOperation/1234567890"
}
bulk-operation-status.response.json{
"data": {
"bulkOperation": {
"id": "gid://shopify/BulkOperation/1234567890",
"status": "COMPLETED",
"errorCode": null,
"objectCount": "15872",
"rootObjectCount": "4210",
"url": "https://storage.googleapis.com/shopify-tiers-assets-prod-us-east1/bulk-operation-outputs/example.jsonl",
"partialDataUrl": null
}
}
}
result.jsonl{"id":"gid://shopify/Order/1111111111","name":"#1001","createdAt":"2026-07-01T08:14:22Z","displayFinancialStatus":"PAID","displayFulfillmentStatus":"FULFILLED","currencyCode":"EUR","totalPriceSet":{"shopMoney":{"amount":"98.00","currencyCode":"EUR"}}}
{"id":"gid://shopify/LineItem/2222222222","sku":"LS-M","quantity":2,"originalUnitPriceSet":{"shopMoney":{"amount":"49.00"}},"__parentId":"gid://shopify/Order/1111111111"}
Written by Lintel. MIT license: free to use in your own store and in client work.
Limits and edge cases
- Without read_all_orders, only orders created in the last 60 days are returned. Public apps need Shopify’s approval for it; apps created in the Dev Dashboard for stores in your own organization don’t.
- The filter takes a date or a full ISO 8601 timestamp, such as created_at:>='2026-07-01T00:00:00Z', when the range must be exact to the second.
- Customer fields such as email and addresses fall under Shopify’s protected customer data rules. Request that access before adding them to the query.
- rootObjectCount counts orders only; objectCount also counts the line items.
Questions
- How do I export Shopify orders by date with GraphQL?
- Run bulkOperationRunQuery with an orders connection filtered by created_at, wait for the operation to complete, then download the JSONL file. For a few hundred orders, a paginated orders query with the same filter is enough.
- Why does my export stop at 60 days?
- read_orders only covers orders created in the last 60 days. Request read_all_orders alongside it to read older orders.
- Can I filter by updated date instead of created date?
- Yes. The orders query accepts updated_at and processed_at filters too, which suits incremental syncs that only pick up changed orders.
- How do I turn the JSONL into a CSV?
- Read the file line by line, keep orders in a map by id, add each line item to its parent with __parentId, then write one CSV row per order or per line item.
Shopify documentation
- Validated against the Admin or Storefront API schema for version 2026-10 on the date shown. Check the version in your request URL.
- IDs and store addresses in the examples are placeholders. Replace them with your own.
- Admin API calls need an access token from your app. Never put an Admin API token in a storefront or theme.
- MIT license. Use the code in your own store or in client work.
Need this built, tested and maintained for your store? See API integrations.
