Skip to main content

Managing Shopify's 20M Discount Code Limit

How to tell whether your store is at risk of hitting Shopify's 20 million discount code cap, how to free up capacity, and how to avoid running into it again.

Shopify caps every store at 20,000,000 individual discount redeem codes. If you run unique-code offers through email, SMS, popups, or automations, it's worth knowing where your store stands before your next major sale, since code creation stops for every app, including Postscript, once a store hits the limit.

IMPORTANT! Before you delete anything:

  • Deletion is permanent. There is no undo, and it is not the same as deactivating a code.

  • Deleting a code that's already in a shopper's hands will break that offer. A shopper holding a live code will see it fail at checkout. Filtering on expired status and times_used:0 is what protects codes still in market.

  • Preview before every bulk run. Run the query version of your filter first and confirm the results are what you expect.

Why This Matters


Shopify enforces a hard limit of 20,000,000 individual discount redeem codes per store. When a store reaches it, code creation stops, for Shopify admin, for Postscript, and for every other app on the store. Shopify's documentation is explicit that third-party apps and custom solutions cannot bypass or raise the limit.

The failure is quiet. Nothing breaks visibly until a campaign tries to generate codes and can't, which for most stores means finding out mid-promotion. If you run unique-code offers through email, SMS, popups, or marketing automation, it's worth knowing where you stand before your next major sale.inimit.

The failure is quiet. Nothing breaks visibly until a campaign tries to generate codes and can't, which for most stores means finding out mid-promotion. If you run unique-code offers through email, SMS, popups, or marketing automation, it's worth knowing where you stand before your next major sale.

How the Limit Actually Works


  • The cap counts individual redeem codes, not parent discounts. A single campaign holding 5 million unique generated codes counts as 5 million against your cap, even though it appears in your admin as one discount. The number of discounts in your store tells you very little about how close you are.

  • Every code counts, whatever its status. Active, scheduled, and expired codes all consume capacity.

  • Only deletion frees capacity. Deactivating a discount or letting it expire does not give you room back. This is the single most common misunderstanding about the limit.

Find Out Where You Stand


  • In Shopify admin → Discounts, you can browse and filter your discounts, but remember that discount count is not code count. Bulk-code campaigns are where the volume hides.

  • If you're a Postscript merchant, your Postscript contact can help you confirm your store's current position against the limit.

Choose Your Cleanup Approach


Most stores near the cap will need the API path. The admin UI is a reasonable first pass if your expired volume is modest.

Method

Best For

Trade-Offs

Shopify admin UI

Small to medium cleanups, targeted passes

No development work required. Can be slow or unreliable at very high code volumes, and selecting every expired discount in one pass isn't dependable at this scale.

GraphQL Admin API

High-volume, automated cleanups

Runs reliably against millions of codes. Requires a custom app or access token with the write_discounts scope.

Method 1: Cleanup via Shopify Admin (No Code Required)


  1. Go to Discounts in your Shopify admin.

  2. Click Filter and select Status → Expired.

  3. Select the discounts you want to remove.

  4. Click Actions → Delete discounts.

Method 2: High-Volume Cleanup via the GraphQL Admin API


For cleanups in the hundreds of thousands or millions, use Shopify's GraphQL Admin API. You'll need a custom app or access token with the write_discounts scope.


Step 1: Preview what you're about to delete

Run discountNodes to review your target discounts before deleting anything. You can refine with status:expired, times_used:0, ends_at, or discount type.

query GetExpiredDiscounts { discountNodes(first: 50, query: "status:expired") { edges { node { id discount { ... on DiscountCodeBasic { title status summary } ... on DiscountCodeBxgy { title status } } } } }}

Step 2: Bulk delete expired discounts

This is the largest and safest win for most stores. discountCodeBulkDelete accepts the same search syntax and launches an asynchronous background job.

mutation BulkDeleteExpiredDiscounts { discountCodeBulkDelete(search: "status:expired") { job { id done } userErrors { field message } }}

API rule: you can supply only one filtering argument per request: search, ids, or savedSearchId. Passing more than one returns an error.

Poll the job rather than assuming the work is finished when the mutation returns. Deletions at this volume take time to complete.


Step 3: Remove unredeemed codes from high-volume discounts

If most of your volume sits in individual redeem codes inside active parent discounts, like ongoing welcome series or always-on winback flows, deleting expired parent discounts won't free enough room. discountCodeRedeemCodeBulkDelete targets codes within one discount, so you'll run it once per high-volume discount.

mutation BulkDeleteUnusedRedeemCodes($discountId: ID!) { discountCodeRedeemCodeBulkDelete( discountId: $discountId, search: "times_used:0" ) { job { id done } userErrors { field message } }}

Filtering on times_used:0 restricts the deletion to codes that were never redeemed.

Reducing How Many Codes You Generate Going Forward


Cleanup buys headroom. These reduce how fast you consume it again.

  • Use automatic or static discounts for sitewide sale-day offers. A blanket promotion delivers the same shopper experience through one automatic discount or one shared code, without generating a code per shopper.

  • Reserve unique codes for offers where uniqueness is doing real work, like enforcing one-per-customer, personalized or VIP offers, and anything where code sharing or resale is a genuine risk.

  • Set end dates on unique-code campaigns so those codes are identifiable as expired later and can be cleaned up in bulk.

  • Run a cleanup pass ahead of each peak period rather than reacting when generation starts failing.

Talking to Shopify


If your store routinely operates near the cap, let your Shopify Account Manager or Merchant Success Manager know. Shopify's published documentation states the limit cannot be raised by apps or custom solutions. Whether Shopify itself will accommodate a higher ceiling for your store and plan is a conversation to have with them directly.

It's worth raising early, but plan your promotions on the assumption that the 20M cap holds, rather than on an increase you haven't been granted.

Quick Reference


Goal

How

Preview what's expired before deleting

discountNodes query with status:expired

Bulk delete expired discounts

discountCodeBulkDelete (search)

Delete unredeemed codes inside one large discount

discountCodeRedeemCodeBulkDelete (discountId + search)

Delete one specific discount

discountCodeDelete (id)

Quick manual cleanup

Shopify admin → Discounts, filter and delete

Shopify Documentation


Get Support


Have questions? Please feel free to reach out to our wonderful Support team at [email protected] or via live chat.

Did this answer your question?