Bulk import data with the GraphQL Admin API
Importing large volumes of data using traditional and synchronous APIs is slow, complex to run, and difficult to manage. Instead of manually running a GraphQL mutation multiple times and managing a client-side throttle, you can run a bulk mutation operation.
Using the GraphQL Admin API, you can bulk import large volumes of data asynchronously. When the operation is complete, the results are delivered in a JSON Lines (JSONL) file that Shopify makes available at a URL.
This guide introduces the bulkOperationRunMutation and shows you how to use it to bulk import data into Shopify.
This feature will be rolling out in the coming weeks.
In API versions 2026-01 and higher, you can run up to five bulk mutation operations at a time per shop. In API versions prior to 2026-01, you can run only one bulk mutation operation at a time per shop. When the operation is complete, the results are delivered in a JSON Lines (JSONL) file that Shopify makes available at a URL.
Anchor to RequirementsRequirements
- You're familiar with creating products, product variants, and collections in your development store.
- You're familiar with performing bulk operations using the GraphQL Admin API.
Anchor to LimitationsLimitations
- In API versions
2026-01and higher, you can run up to five bulk mutation operations at a time per shop. In API versions prior to2026-01, you can run only one bulk operation of each type (bulkOperationRunMutationorbulkOperationRunQuery) at a time per shop. - In API versions
2026-01and higher, apps are limited to 25,000 bulk mutation operations per shop within a rolling 24-hour period.
-
The bulk mutation operation has to complete within 24 hours. After that it will be stopped and marked as
failed.When your import runs into this limit, consider reducing the input size.
- You can supply any GraphQL Admin API mutation to the
bulkOperationRunMutation, except forbulkOperationRunMutationandbulkOperationRunQuerythemselves (to prevent recursion).
- The mutation that's passed into
bulkOperationRunMutationis limited to one connection field, which is defined by the GraphQL Admin API schema.
- The size of the JSONL file can't exceed 100MB.
Anchor to How bulk importing data worksHow bulk importing data works
You initiate a bulk operation by supplying a mutation string in the bulkOperationRunMutation. Shopify then executes that mutation string asynchronously as a bulk operation.
Most GraphQL Admin API requests that you make are subject to rate limits, but the bulkOperationRunMutation request isn't. Because you're only making low-cost requests for creating operations, polling their status, or canceling them, bulk mutation operations are an efficient way to create data compared to standard GraphQL API requests.
Anchor to Listing and filtering bulk operationsListing and filtering bulk operations
In API versions 2026-01 and higher, you can use the bulkOperations query to list, filter, and paginate your bulk operations. bulkOperations replaces the deprecated currentBulkOperation query.
The bulkOperations query provides the following features:
-
Filtering by status, such as
completed,running, orfailed. -
Filtering by operation type, such as query or mutation.
-
Sorting by values such as creation date, completion date, status, or ID.
-
Pagination with cursor-based navigation.
The
bulkOperationquery replaces the deprecatedcurrentBulkOperationquery by allowing a direct lookup of a specific operation by ID usingbulkOperation(id:).
For complete details, refer to the bulkOperations and bulkOperation query reference.
The following diagram shows the steps involved in bulk importing data into Shopify:

-
Create a JSONL file and include GraphQL variables: Include the variables for the mutation in a JSONL file format. Each line in the JSONL file represents one input unit. The mutation runs once on each line of the input file.
-
Upload the file to Shopify: Before you upload the file, you must reserve a link by running the
stagedUploadsCreatemutation. After the space has been reserved, you can upload the file by making a request using the information returned from thestagedUploadsCreateresponse. -
Create a bulk mutation operation: After the file has been uploaded, you can run
bulkOperationRunMutationto create a bulk mutation operation. ThebulkOperationRunMutationimports data in bulk by running the supplied GraphQL API mutation with the file of variables uploaded in the last step. -
Wait for the operation to finish: To determine when the bulk mutation has finished, you can either:
- Subscribe to a webhook topic: You can use the
webhookSubscriptionCreatemutation to subscribe to thebulk_operations/finishwebhook topic in order to receive a webhook when any operation finishes - in other words, it has completed, failed, or been cancelled.
- Poll the status of the operation: While the operation is running, you can poll to see its progress by querying the specific bulk operation using its ID (returned from the
bulkOperationRunQuerymutation). In API version2026-01and higher, use thebulkOperation(id:)query. In API versions prior to 2026-01, use thecurrentBulkOperationquery. TheobjectCountfield increments to indicate the operation's progress, and thestatusfield returns whether the operation is completed.
- Subscribe to a webhook topic: You can use the
-
Retrieve the results: When a bulk mutation operation is completed, a JSONL output file is available for download at the URL specified in the
urlfield.
Anchor to Create a JSONL file and include GraphQL variablesCreate a JSONL file and include Graph QL variables
When adding GraphQL variables to a new JSONL file, you need to format the variables so that they are accepted by the corresponding bulk operation GraphQL API. The format of the input variables need to match the GraphQL Admin API schema.
For example, you might want to import a large quantity of products. Each attribute of a product must be mapped to existing fields defined in the GraphQL input object ProductInput. In the JSONL file, each line represents one product input. The GraphQL Admin API runs once on each line of the input file. One input should take up one line only, no matter how complex the input object structure is.
The following example shows a sample JSONL file that is used to create 10 products in bulk:
The GraphQL Admin API doesn't serially process the contents of the JSONL file. Avoid relying on a particular sequence of lines and object order to achieve a desired result.
Anchor to Upload the file to ShopifyUpload the file to Shopify
After you've created the JSONL file, and included the GraphQL variables, you can upload the file to Shopify. Before uploading the file, you need to first generate the upload URL and parameters.
Anchor to Generate the uploaded URL and parametersGenerate the uploaded URL and parameters
You can use the stagedUploadsCreate mutation to generate the values that you need to authenticate the upload. The mutation returns an array of stagedMediaUploadTarget instances.
An instance of stagedMediaUploadTarget has the following key properties:
parameters: The parameters that you use to authenticate an upload request.url: The signed URL where you can upload the JSONL file that includes GraphQL variables.
The mutation accepts an input of type stagedUploadInput, which has the following fields:
| Field | Type | Description |
|---|---|---|
resource | enum | Specifies the resource type to upload. To use bulkOperationRunMutation, the resource type must be BULK_MUTATION_VARIABLES. |
filename | string | The name of the file to upload. |
mimeType | string | The media type of the file to upload. To use bulkOperationRunMutation, the mimeType must be "text/jsonl". |
httpMethod | enum | The HTTP method to be used by the staged upload. To use bulkOperationRunMutation, the httpMethod must be POST. |
Anchor to ExampleExample
The following example uses the stagedUploadsCreate mutation to generate the values required to upload a JSONL file and be consumed by the bulkOperationRunMutation. You must first run the stagedUploadsCreate mutation with no variables, and then separately send a POST request to the staged upload URL with the JSONL data:
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Upload the JSONL fileUpload the JSONL file
After you generate the parameters and URL for an upload, you can upload the JSONL file using a POST request. You must use a multipart form, and include all parameters as form inputs in the request body.
To generate the parameters for the multipart form, start with the parameters returned from the stagedUploadsCreate mutation. Then, add the file attachment.
The file parameter must be the last parameter in the list. If you add the file parameter somewhere else, then you'll receive an error.
After uploading your JSONL file, don't modify or replace the file at the staged upload URL while the bulk operation is running. The system validates the file's integrity using checksums, and any modifications will cause the operation to fail with an INTERNAL_SERVER_ERROR.
POST request
GraphQL variables in JSONL file
Anchor to Create a bulk mutation operationCreate a bulk mutation operation
After you upload the file, you can run bulkOperationRunMutation to import data in bulk. You must supply the corresponding mutation and the URL that you obtained in the previous step.
The bulkOperationRunMutation mutation takes the following arguments:
| Field | Type | Description |
|---|---|---|
mutation | string | Specifies the GraphQL API mutation that you want to run in bulk. Valid values: productCreate, collectionCreate, productUpdate, productUpdateMedia |
stagedUploadPath | string | The path to the file of inputs in JSONL format to be consumed by stagedUploadsCreate |
Anchor to ExampleExample
In the following example, you want to run the following productCreate mutation in bulk:
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL mutation
To run the productCreate mutation in bulk, pass the mutation as a string into bulkOperationRunMutation:
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL mutation
JSON response
Anchor to Wait for the operation to finishWait for the operation to finish
Subscribing to the webhook topic is recommended over polling as it limits the number of redundant API calls.
Anchor to Option A. Subscribe to the ,[object Object], webhook topicOption A. Subscribe to the bulk_operations/finish webhook topic
bulk_operations/finish webhook topicUsing webhooks with bulk operations is only available in Admin API version 2021-10 and higher.
You can use the webhookSubscriptionCreate mutation to subscribe to the bulk_operations/finish webhook topic in order to receive a webhook when any operation finishes - in other words, it has completed, failed, or been cancelled.
For full setup instructions, refer to Configuring webhooks.
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL mutation
JSON response
After you've subscribed to the webhook topic, Shopify sends a POST request to the specified URL any time a bulk operation on the store (both mutations and queries) finishes.
Example webhook response
You now must retrieve the bulk operation's data URL by using the node field and passing the admin_graphql_api_id value from the webhook payload as its id:
POST https://{shop}.myshopify.com/api/{api_version}/graphql.json
GraphQL query
JSON response
For more information on how webhooks work, refer to Webhooks.
Webhook delivery isn't always guaranteed, so you might still need to poll for the operation's status to check when it's finished.
Anchor to Option B. Poll the status of the operationOption B. Poll the status of the operation
While the operation is running, you can poll to see its progress by querying the specific bulk operation using its ID, which is returned from the bulkOperationRunMutation mutation.
In API versions 2026-01 and higher, use the bulkOperation(id:) query. In API versions prior to 2026-01, use the currentBulkOperation query. The objectCount field increments to indicate the operation's progress, and the status field returns whether the operation is completed.
You can adjust your polling intervals based on the amount of data that you import. To learn about other possible operation statuses, refer to the BulkOperationStatus reference documentation.
In API versions 2026-01 and higher:
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL query
JSON response
In API versions prior to 2026-01 (using the deprecated currentBulkOperation query):
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL query
Anchor to Retrieve the resultsRetrieve the results
When a bulk mutation operation is finished, you can download a result data file.
If an operation successfully completes, then the url field contains a URL where you can download the data file. If an operation fails, but some data was retrieved before the failure occurred, then a partially complete data file is available at the URL specified in the partialDataUrl field.
In either case, the returned URLs are authenticated and expire after one week.
After you've downloaded the data, you can parse it according to the JSONL format. Since both input and response files are in JSONL, each line in the final asset file represents the response of running the mutation on the corresponding line in the input file.
Anchor to Operation successOperation success
The following example shows the response for a product that was successfully created:
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
JSON response
Anchor to Operation failuresOperation failures
Bulk operations provide detailed per-line error handling. Each mutation in your JSONL file is validated and executed independently, with errors reported in the output file alongside successful results.
Anchor to Error handling behaviorError handling behavior
Errors are handled at the line level and reported in the output file:
- JSON parse errors: Invalid JSON format in a JSONL line appears as an error for that specific line in the output.
- Validation errors: GraphQL query validation failures, such as invalid fields or missing required arguments, display as errors for the affected line.
- Execution errors: Mutation failures during execution, such as business logic errors or permission issues, display in the output with detailed error messages.
- Access denied errors: Missing access scopes are reported for each line in the output file with details about which fields caused the issue.
The bulk operation only fails entirely (with status: FAILED) for critical system errors:
INTERNAL_SERVER_ERROR: Something went wrong on Shopify's server and we've been notified of the error. These errors might be intermittent, so you can try making your request again.
To learn about the other possible operation error codes, refer to the BulkOperationErrorCode reference documentation.
Anchor to Best practicesBest practices
- Review the output JSONL file to identify which specific mutations failed and why.
- Each error includes the line number from your input file, making it easy to identify failing mutations.
- Test individual mutations first to validate your access scopes and mutation structure before running bulk operations.
When using the bulk_operations/finish webhook, the error_code and status fields in the webhook payload will be lowercase. For example, failed instead of FAILED.
Anchor to Error examples in output filesError examples in output files
When a mutation fails, the error appears in the output JSONL file for that specific line. Here are common error formats:
Anchor to Validation errorValidation error
If the input has the correct format, but one or more values failed validation, then the line in the output file looks like the following:
Anchor to Unrecognizable field errorUnrecognizable field error
If the input has an unrecognizable field, then the line in the output file looks like the following:
This check is executed by comparing the input against the productInput object, which is specified as part of the mutation argument.
Anchor to Manage concurrent operationsManage concurrent operations
In API versions 2026-01 and higher, you can run up to 5 bulk mutation operations concurrently per shop. This enables you to import multiple datasets simultaneously without waiting for each operation to complete.
Anchor to Run concurrent operationsRun concurrent operations
To start a new bulk operation while others are running, call bulkOperationRunMutation again with a different staged upload URL and mutation:
POST https://{shop}.myshopify.com/admin/api/2026-01/graphql.json
GraphQL mutation
Each operation runs independently and returns its own ID. You can track each operation separately using bulkOperation(id:) or view all operations together using the bulkOperations query.
Anchor to View all running operationsView all running operations
Use the bulkOperations query to see all your bulk operations, including those currently running:
POST https://{shop}.myshopify.com/admin/api/2026-01/graphql.json
GraphQL query
This query returns all currently running bulk mutation operations, allowing you to monitor progress across multiple concurrent operations.
For complete details on filtering and pagination, refer to the bulkOperations query reference.
Anchor to Cancel an operationCancel an operation
To cancel an in-progress bulk operation, run the bulkOperationCancel mutation and supply the operation ID as an input variable:
POST https://{shop}.myshopify.com/admin/api/{api_version}/graphql.json
GraphQL query
JSON response
Anchor to Next stepsNext steps
- Consult our reference documentation to learn more about creating and managing bulk operations.
- Learn how to use bulk operations to asynchronously fetch data in bulk.