Skip to content

Shopify Dude Complete Guide

One-Time vs Subscription Discounts in Shopify Functions: Stop Filtering Only in Your Function

Shopify now enforces purchase-type filtering for app discounts at checkout. Here’s how to keep one-time and subscription discount behavior aligned with your Function and admin configuration.

Quick answer

Shopify now enforces the app-discount fields appliesOnOneTimePurchase and appliesOnSubscription at checkout. If a discount should apply only to one-time lines or only to subscription lines, configure the discount itself correctly instead of relying only on filtering inside your Shopify Function. Your Function can still choose candidates, but Shopify applies purchase-type filtering at the platform level afterward.

On this page

Why this is easy to get wrong

For a long time, app discounts exposed purchase-type fields that did not actually affect checkout. Developers who needed “one-time only” or “subscription only” behavior therefore implemented the rule inside the Discount Function: inspect the selling plan, reject the wrong lines, and return only eligible candidates.

Shopify changed that behavior on June 17, 2026. Purchase-type settings on app discounts are now enforced at checkout. Existing discounts were backfilled to allow both one-time and subscription purchases, so old discounts do not suddenly change behavior, but new and updated discount configuration can now express the rule natively.

What to change in a production implementation

Think of the system as two layers. The Function decides which lines are candidates according to your business logic. The app discount configuration tells Shopify which purchase types the discount is allowed to affect.

For a one-time-only promotion, configure the discount so one-time purchases are enabled and subscription purchases are disabled. For subscription-only behavior, do the reverse. If both are valid, enable both.

Do not assume that returning a subscription line from the Function overrides the discount configuration. Shopify performs purchase-type filtering after the Function runs, so a candidate that conflicts with the configured purchase type is excluded.

If you provide a Discount Function settings UI, API version 2026-04 also exposes purchaseType and recurringCycleLimit through the discounts plugin. That lets the merchant configure one-time/subscription behavior and subscription cycle limits without a separate custom admin screen.

A durable pattern

  1. Make purchase type explicit in the discount configuration.
  2. Keep product, metafield, customer, quantity, and other business rules in the Function.
  3. If selling plans matter to the Function’s own logic, continue querying them; just do not make that your only enforcement layer.
  4. Expose the purchase-type choice in the app’s discount settings when merchants need control.
  5. Test mixed carts containing both a one-time line and a subscription line.

Common misunderstanding

“My Function returned only the lines I wanted, so the discount configuration does not matter.”

It does matter. Shopify’s platform-level purchase-type filter runs after the Function. A line can be a valid Function candidate and still be excluded because the app discount is not configured for that purchase type.

How to test this

Use a product that can be purchased both once and through a selling plan. Put one of each purchase type in the same cart. Test three configurations: one-time only, subscription only, and both. Confirm the discount affects exactly the intended lines. If you support subscription cycle limits, also verify the configured recurringCycleLimit rather than testing only the first checkout.

Sources and further reading