Shopify Functions & APIs

Shopify Functions: Build a Custom Volume Discount Step by Step

By CartStack Team3 min read

Shopify Functions let you change how checkout logic works by running your own code on Shopify’s servers. In this guide, you will build a volume discount that takes 10% off any line with three or more units. You will also test it locally and deploy it.

Cover graphic for a Shopify Functions volume discount tutorial
Shopify Functions run your logic on Shopify infrastructure.

What Shopify Functions can do

A function is a small program that Shopify runs at a specific point in the cart or checkout. It receives input data from a GraphQL query. Then it returns operations that Shopify applies.

You can customize several areas. These include discounts, delivery options, payment methods, cart validation and cart transforms. Because functions run on Shopify’s infrastructure, they stay fast and scale with your traffic.

Functions also replace Shopify Scripts, so new customizations should use them. Check Shopify’s documentation for the current status of Scripts.

Set up your app

Functions live inside an app. First, install the Shopify CLI and create an app. Then generate a discount extension.

shopify app init
cd volume-discounts
shopify app generate extension

When the CLI asks, choose the discount function template and pick JavaScript or TypeScript. The exact file names depend on your API version, so treat the code below as a pattern.

Write the Shopify Functions discount logic

Start with the input query. It lists the data your function needs and nothing more.

query CartInput {
  cart {
    lines {
      id
      quantity
    }
  }
  discount {
    discountClasses
  }
}

Next, write the logic. The function checks each cart line. Then it targets lines with three or more units.

import { DiscountClass, ProductDiscountSelectionStrategy } from '../generated/api';

export function cartLinesDiscountsGenerateRun(input) {
  const classes = input.discount.discountClasses;
  if (!classes.includes(DiscountClass.Product)) {
    return { operations: [] };
  }

  const targets = input.cart.lines
    .filter((line) => line.quantity >= 3)
    .map((line) => ({ cartLine: { id: line.id } }));

  if (targets.length === 0) {
    return { operations: [] };
  }

  return {
    operations: [{
      productDiscountsAdd: {
        candidates: [{
          message: '10% off 3 or more',
          targets,
          value: { percentage: { value: 10 } },
        }],
        selectionStrategy: ProductDiscountSelectionStrategy.First,
      },
    }],
  };
}

The function returns an empty list when nothing qualifies. As a result, Shopify applies no discount. This is the safe default.

Test Shopify Functions locally

You do not need to deploy to test. Instead, run the function against a sample input.

shopify app function run

The CLI asks for input JSON or reads it from a file. Try one cart with two units and another with three. Then confirm the output matches your expectation. Also, keep queries small, because functions run in a sandbox with strict limits on runtime and input size.

Deploy and create the discount

When your tests pass, deploy the app. Next, create a discount that uses your function.

shopify app deploy

After deployment, open the Discounts page in the Shopify admin. Your function appears as a discount type. Alternatively, create the discount with the Admin GraphQL API. See the Shopify Functions documentation for the current mutations and API versions.

Need to load large catalogs to configure discounts? Read our guide to Shopify GraphQL pagination.

FAQ about Shopify Functions

Which languages can I use? JavaScript and TypeScript work out of the box. Rust is another common choice for heavy logic.

Do Shopify Functions need an app? Yes. You package them as an extension of an app.

Are Shopify Functions available on every plan? Availability depends on the function type and your plan. Check the docs before you promise a feature to a client.