Shopify Discount Selection Strategy: Maximum vs. First vs. All

A setting inside the Discount Function API resolves competing discounts, but developers keep hitting the same misconception about what it actually controls.

A merchant runs two automatic product discounts, sets one function to selectionStrategy MAXIMUM, and expects that to stop the discounts from stacking with anything else in the cart. Then a separate order discount applies on top anyway, and the support ticket that follows usually assumes something's broken. Nothing is. The selection strategy was never controlling that.

Shopify's discount selection strategy (ALL, FIRST, MAXIMUM) determines how a single discount function resolves competing candidates within its own output, not how that discount interacts with other, separate discounts in the cart. Confusing those two things is the single most common mistake developers make when building custom discount functions.

What does each selection strategy actually do?

FIRST applies the first eligible candidate a function generates and ignores the rest; MAXIMUM applies whichever eligible candidate gives the customer the biggest discount; ALL applies every eligible candidate the function produces, though ALL's availability differs by discount class. Shopify's Discount Function API reference defines selectionStrategy as the strategy applied to the list of products eligible for a cart line discount, with ALL, FIRST, and MAXIMUM as the documented values for product discounts specifically.

Order discounts and shipping discounts don't all support the same set. One deep-dive into the API's actual behavior is specific about this: product discounts support ALL, FIRST, and MAXIMUM; order discounts support only FIRST and MAXIMUM; delivery discounts currently use ALL. A rule built assuming ALL works identically everywhere will fail silently on the order-discount half of that logic.

Why do developers keep assuming selection strategy controls cross-discount stacking?

The name and the mental model both suggest "which discount wins," which naturally reads as an answer to "will this combine with other discounts," but selection strategy only resolves competition among candidates the same function generates internally. The same deep-dive states this plainly: selection strategies decide how candidates from one operation compete inside your function's own output. Cross-discount stacking, whether one discount combines with a separate, different discount, is governed entirely by the discount node's combination settings and Shopify's discount engine, not by selectionStrategy.

That's a two-layer system a lot of documentation compresses into one concept. Layer one: your function might generate three possible discounts for the same product, and selectionStrategy decides which of those three actually applies. Layer two: whether your function's chosen discount then combines with an entirely separate discount object elsewhere in the cart is a different setting, configured on each discount's Combinations options, unrelated to selectionStrategy.

What goes wrong when developers expect ALL to apply to multiple products?

A frequent, well-documented complaint is that a function generating multiple per-product discounts only applies one of them, even when the array contains several, because the strategy in use resolves to a single winner instead of applying every candidate. A Shopify developer community thread documents this exactly: a function outputting an array of per-product discounts saw only one product actually discounted at checkout, traced to using MAXIMUM (or an older strategy name, discountApplicationStrategy) instead of ALL. The fix required explicitly setting ALL and verifying variant IDs were correctly targeted, since ALL's availability and behavior varied across API versions during rollout.

A related feature-request thread shows this was a genuine platform gap for a period: developers needed to discount different products at different tiers within one function (Product 1 at 10%, Product 2 at 30%) and initially had no strategy that applied more than one candidate at once. ALL was added specifically to close this, though one follow-up thread notes ALL's rollout wasn't uniform across API versions, so version-pinning matters if you're relying on it.

How does this play out in a no-code discount builder instead of custom code?

A visual discount builder abstracts selectionStrategy into an explicit choice at the rule level, which removes the API-version pitfalls but not the underlying two-layer logic: within-rule resolution still needs to be set correctly, and cross-rule combination is still a separate setting. Flowly: Discount Functions exposes First, All, Maximum, and Minimum as explicit selection strategy options when a rule could produce more than one qualifying outcome, most commonly in tiered pricing where a cart might satisfy multiple thresholds at once.

For a tiered volume discount (buy 3 for 10% off, buy 6 for 20%, buy 10 for 30%), Maximum is almost always the correct choice, since it resolves to whichever tier gives the customer the best deal they've actually earned. First would apply whichever tier was built first regardless of which is more generous, which is rarely the intended behavior for a volume incentive. Flowly's docs cover exactly how each strategy resolves against multi-tier rules.

Selection strategy comparison

Strategy

What it resolves

Typical use case

FIRST

Applies the first eligible candidate, ignores the rest

Simple, single-outcome rules where order doesn't matter

MAXIMUM

Applies whichever eligible candidate gives the biggest discount

Tiered/volume pricing with multiple possible thresholds

ALL

Applies every eligible candidate the function generates

Multiple distinct products each needing their own discount amount

MINIMUM

Applies whichever eligible candidate gives the smallest discount

Conservative fallback when overlapping rules shouldn't stack generously

FAQ

Does selection strategy control whether two separate discounts combine?

No. Selection strategy resolves competing candidates generated by a single discount function. Whether that discount combines with a different, separate discount is controlled by each discount's own Combinations settings, a completely different mechanism.

Why did my discount function only apply to one product when I expected several?

This is the most common selection-strategy support issue: if the strategy in use resolves to a single winner (FIRST or MAXIMUM) instead of ALL, only one candidate from your function's output gets applied, even if your function generated discounts for multiple products.

Do all discount classes support the same selection strategies?

No. Product discounts support ALL, FIRST, and MAXIMUM. Order discounts support only FIRST and MAXIMUM. Delivery (shipping) discounts currently use ALL. Building logic that assumes uniform support across classes is a common source of silent failures.

Which selection strategy should I use for a tiered volume discount?

MAXIMUM, in almost every case. It ensures a cart that qualifies for multiple tiers gets the best one the customer has actually earned, rather than whichever tier happens to be evaluated first.

Do no-code discount builders still require understanding selection strategy?

Yes, at the rule level. A visual builder like Flowly exposes the same First/All/Maximum/Minimum choice explicitly, so understanding what each one resolves still matters even without writing the underlying Function code.

If a rule you built is only discounting one product when it should be discounting several, or applying the wrong tier in a volume discount, the selection strategy is usually where to look first. Download Flowly directly from the Shopify App Store and set explicit selection strategies without touching the underlying API version quirks, or book a call with Subscribfy's team if your discount logic spans multiple products or tiers that need careful resolution.

Image

Book a meeting with our sales team now!

Create predictable revenue from the customers you already have.