Require a minimum order value
A Shopify validation Function that blocks checkout below a minimum order value set in your store currency and converted for each market. Tested JavaScript.
- Function API
- Cart and Checkout Validation
- Target
- cart.validations.generate.run
- Plan
- Any plan in a public app; Shopify Plus in a custom app
- App scope
- write_validations
- API version
- 2026-10
- Last checked
In short
This validation Function blocks checkout when the cart subtotal is below a minimum, 500 in your store currency by default, converted to the customer’s currency. Customers can still build their cart freely; the rule applies from checkout on. It uses the cart.validations.generate.run target of the Cart and Checkout Validation API, version 2026-10, on any plan in a public app.
How to use it
- Create an app with the Shopify CLI and add the extension: shopify app generate extension --template cart_checkout_validation, with JavaScript.
- Replace the generated shopify.extension.toml and the two files in src/ with the files below.
- Run the fixtures with shopify app function run --input tests/below-minimum-at-checkout.input.json.
- Deploy with shopify app deploy and turn the validation on with validationCreate.
- Set the minimum and message in the validation’s $app:function-configuration metafield, for example {"minimumAmount": 250}.
Code
shopify.extension.tomlapi_version = "2026-10"
[[extensions]]
name = "Minimum order value"
handle = "minimum-order-value"
type = "function"
[[extensions.targeting]]
target = "cart.validations.generate.run"
input_query = "src/cart_validations_generate_run.graphql"
export = "cart-validations-generate-run"
[extensions.build]
command = ""
path = "dist/function.wasm"
src/cart_validations_generate_run.graphqlquery CartValidationsGenerateRunInput {
buyerJourney {
step
}
cart {
cost {
subtotalAmount {
amount
}
}
}
presentmentCurrencyRate
validation {
metafield(namespace: "$app", key: "function-configuration") {
jsonValue
}
}
}
src/cart_validations_generate_run.js// @ts-check
/**
* @typedef {import("../generated/api").CartValidationsGenerateRunInput} CartValidationsGenerateRunInput
* @typedef {import("../generated/api").CartValidationsGenerateRunResult} CartValidationsGenerateRunResult
*/
/** Settings stored as JSON in the validation's metafield. */
const DEFAULT_CONFIG = {
// In the store's currency; converted to the customer's currency below.
minimumAmount: 500,
// {amount} is replaced with the converted minimum.
message: "The minimum order value is {amount}. Add a few more items to check out.",
};
/** Errors about the cart as a whole show at the top of checkout and on the cart. */
const CART_TARGET = "$.cart";
/** @type {CartValidationsGenerateRunResult} */
const NO_ERRORS = { operations: [] };
/**
* @param {CartValidationsGenerateRunInput} input
* @returns {CartValidationsGenerateRunResult}
*/
export function cartValidationsGenerateRun(input) {
// Let customers keep adding to the cart freely; enforce the rule from checkout on.
if (input.buyerJourney.step === "CART_INTERACTION") return NO_ERRORS;
const config = { ...DEFAULT_CONFIG, ...input.validation?.metafield?.jsonValue };
// The cart is priced in the customer's currency; the minimum is set in the store's.
const minimum = config.minimumAmount * Number(input.presentmentCurrencyRate);
const subtotal = Number(input.cart.cost.subtotalAmount.amount);
if (subtotal >= minimum) return NO_ERRORS;
const message = config.message.replace("{amount}", minimum.toFixed(2));
return { operations: [{ validationAdd: { errors: [{ message, target: CART_TARGET }] } }] };
}
Test input and expected output
tests/below-minimum-at-checkout.input.json{
"buyerJourney": { "step": "CHECKOUT_COMPLETION" },
"cart": { "cost": { "subtotalAmount": { "amount": "420.0" } } },
"presentmentCurrencyRate": "1.0",
"validation": { "metafield": null }
}
tests/below-minimum-at-checkout.output.json{
"operations": [
{
"validationAdd": {
"errors": [
{ "message": "The minimum order value is 500.00. Add a few more items to check out.", "target": "$.cart" }
]
}
}
]
}
tests/below-minimum-in-cart.input.json{
"buyerJourney": { "step": "CART_INTERACTION" },
"cart": { "cost": { "subtotalAmount": { "amount": "420.0" } } },
"presentmentCurrencyRate": "1.0",
"validation": { "metafield": null }
}
tests/below-minimum-in-cart.output.json{ "operations": [] }
tests/converted-minimum-met.input.json{
"buyerJourney": { "step": "CHECKOUT_INTERACTION" },
"cart": { "cost": { "subtotalAmount": { "amount": "95.0" } } },
"presentmentCurrencyRate": "0.031",
"validation": { "metafield": { "jsonValue": { "minimumAmount": 3000 } } }
}
tests/converted-minimum-met.output.json{ "operations": [] }
Written by Lintel. MIT license: free to use in your own store and in client work.
Limits and edge cases
- The subtotal is before taxes and cart-level discounts, as Shopify defines cart.cost.subtotalAmount.
- The minimum is converted with presentmentCurrencyRate; with fixed local prices per market, the converted figure may not be a round number.
- Errors are skipped while the buyer journey step is CART_INTERACTION and returned at checkout interaction and completion.
Questions
- How do I set a minimum order amount on Shopify?
- Use a cart and checkout validation Function that compares the subtotal with your minimum and blocks checkout below it, as this example does.
- Will customers see the message on the cart page?
- Not with this code; it waits until checkout so the cart stays usable. Remove the CART_INTERACTION check if you want the message on the cart as well.
- Can wholesale customers have a different minimum?
- Yes. Add cart.buyerIdentity.purchasingCompany or a customer tag check to the input query and use a second amount for them.
Shopify documentation
- Written for Function API version 2026-10 and checked against Shopify’s reference on the date shown. Shopify releases a new version every quarter.
- Custom apps that contain Functions only run on Shopify Plus stores; a public app with the same Function runs on any plan unless the page says otherwise.
- Every example ships with test fixtures, and we run them before publishing. Run them again after you change the code: shopify app function run.
- MIT license. Use the code in your own store or in client work.
Need this built, tested and maintained for your store? See Shopify Functions development.
