Priorities & Strategies
When a discount function contains multiple rule groups, the system must determine which rules to evaluate and how to combine their results. This is controlled through two mechanisms: priority ordering (which rule evaluates first) and strategy modes (how many rules can match). Understanding these concepts is essential for building multi-rule configurations that behave predictably.
Priority Ordering
Rule groups have no priority field. The order of the ruleGroups array sets the evaluation order.
- The first rule group in the array evaluates first. The editor shows each position as a Priority N badge, where N is the array index plus one.
- To change the order, use Move up or Move down on the rule card in the editor.
[
{ "id": "rule_vip", "name": "VIP Discount" },
{ "id": "rule_sale", "name": "Seasonal Sale" },
{ "id": "rule_general", "name": "General Discount" }
]
In this example, the VIP rule is always evaluated first, followed by the seasonal sale, and finally the general discount.
Strategy Modes
The strategy field on the discount configuration determines how many rule groups can contribute to the final discount output. There are two modes:
“first” (Default)
The function stops at the first matching rule group and returns its discount. No subsequent rule groups are evaluated.
This is the default behavior when no strategy is specified. It creates a “waterfall” pattern where rule groups act as a priority-ordered list of mutually exclusive options.
{
"strategy": "first",
"ruleGroups": [
{
"id": "rule_vip",
"name": "VIP 25% Off",
"conditions": [
{ "type": "customerTag", "operator": "hasAny", "tags": ["VIP"] }
]
},
{
"id": "rule_general",
"name": "Everyone 10% Off",
"conditions": []
}
]
}
In this configuration:
- VIP customers receive 25% off (rule 1 matches, evaluation stops).
- All other customers receive 10% off (rule 1 fails, rule 2 matches).
- A VIP customer never receives the 10% general discount because the first match terminates evaluation.
”all”
The function evaluates all rule groups and combines the results. Every matching rule group contributes its discount to the output.
{
"strategy": "all",
"ruleGroups": [
{
"id": "rule_volume",
"name": "Volume Discount 5%",
"conditions": [
{ "type": "cartTotalQuantity", "operator": "greaterThanOrEqual", "value": 10 }
]
},
{
"id": "rule_category",
"name": "Outerwear 10% Off",
"conditions": [
{ "type": "productTag", "operator": "hasAny", "tags": ["outerwear"] }
]
}
]
}
In this configuration:
- A cart with 10+ items where some are outerwear would produce both discounts: volume discount on all eligible items and category discount on outerwear items.
- Each rule group independently evaluates its conditions and contributes its own discount candidates.
Selection Strategies (Shopify-Level)
After your discount function returns its candidates, Shopify applies a selection strategy to each discount operation. The function sets that strategy in its output. Two settings in the editor change it for product and order discounts.
| Operation Type | Default | Setting in the editor | Config field and values |
|---|---|---|---|
ProductDiscountsAdd | Maximum: Shopify picks the highest-value candidate | Product discount stacking | productSelectionStrategy: "maximum" (Apply highest discount), "all" (Apply all matching discounts), "first" (First match only) |
OrderDiscountsAdd | Maximum: Shopify picks the highest-value candidate | Order discount stacking | orderSelectionStrategy: "maximum" (Apply highest discount), "first" (First match only) |
DeliveryDiscountsAdd | All: every shipping candidate applies | None | None |
Key Implications
- Product discounts apply only the highest-value candidate by default. Choose Apply all matching discounts to apply every product candidate. Two exceptions make the product operation apply all candidates: a Volume & Tiered rule group with
tierType"lineQuantity"that has an eligible line, and a fixed price that gives candidates on two or more lines when no line is the target of two candidates. - Order discounts from a single function never stack. Shopify applies the highest-value order candidate, or the first one with First match only.
- Shipping discounts from a single function all apply.
Strategy vs. Stacking
It is important to distinguish between strategy (within one function) and stacking (across functions and discounts):
| Concept | Scope | Controlled By |
|---|---|---|
| Strategy | Within a single discount function | The strategy field in your configuration |
| Stacking | Across multiple discounts and functions | Shopify’s combinesWith settings on the discount |
Strategy determines which rule groups within your single function produce output. For example, with the "first" strategy, only one rule group can win.
Stacking determines whether your discount can combine with other discounts on the store. This is configured at the Shopify discount level through the combinesWith object, which specifies whether your discount can stack with product discounts, order discounts, and/or shipping discounts from other sources.
Examples
Example 1: “First” Strategy for Tiered Customer Pricing
A common pattern uses the “first” strategy with descending priority to create tiered pricing based on customer segments:
{
"strategy": "first",
"ruleGroups": [
{
"id": "tier_platinum",
"name": "Platinum Members - 30% Off",
"enabled": true,
"conditionLogic": "and",
"conditions": [
{ "type": "customerTag", "operator": "hasAny", "tags": ["platinum"] }
]
},
{
"id": "tier_gold",
"name": "Gold Members - 20% Off",
"enabled": true,
"conditionLogic": "and",
"conditions": [
{ "type": "customerTag", "operator": "hasAny", "tags": ["gold"] }
]
},
{
"id": "tier_silver",
"name": "Silver Members - 10% Off",
"enabled": true,
"conditionLogic": "and",
"conditions": [
{ "type": "customerTag", "operator": "hasAny", "tags": ["silver"] }
]
}
]
}
A customer tagged as both “platinum” and “gold” receives only the 30% platinum discount because evaluation stops at the first match.
Example 2: “All” Strategy for Stacking Volume and Category Discounts
When discounts should be additive, use the “all” strategy:
{
"strategy": "all",
"ruleGroups": [
{
"id": "volume_discount",
"name": "Buy 5+ Items - 5% Off",
"enabled": true,
"conditionLogic": "and",
"conditions": [
{ "type": "cartTotalQuantity", "operator": "greaterThanOrEqual", "value": 5 }
]
},
{
"id": "category_discount",
"name": "Electronics - 10% Off",
"enabled": true,
"conditionLogic": "and",
"conditions": [
{ "type": "collection", "operator": "inAny", "collectionIds": ["gid://shopify/Collection/123456789"] }
]
}
]
}
A cart with 5+ items that includes electronics would receive both discounts: 5% off all items from the volume rule and an additional 10% off electronics from the category rule.