Skip to main content

Build a Discount Function

With Shopify Functions, you can create a new type of discount that applies to cart lines, order subtotal, and shipping rates.

In this tutorial, you'll use Shopify Functions to create a new type of discount that does three things:

  • Reduces the price of a cart line by 20%
  • Discounts the order subtotal by 10%
  • Provides free shipping

After creating the discount, you can test it out in your store.

Migrate your existing discount functions

To learn how to migrate your existing Discount Functions to use the Discount API, refer to Migrate to the Discount API.

In this tutorial, you'll learn how to do the following tasks:

  • Use the Shopify CLI to add a Discount Function to an app
  • Review the configuration of your discount function
  • Review the input queries associated with your discount function
  • Review the function logic associated with your discount function
  • Deploy your updated app with new access scopes
  • Use GraphiQL to create a discount and configure it to work with your function
  • Test your discount function and view its logs
A checkout summary that lists discounts for all three classes

Requirements

Create an app

Create an that has the write_discounts and read_products access scopes, using Shopify CLI 3.72.1 or higher.

Install Node.js

Install Node.js 22 or higher.

You've installed rust

On Windows, Rust requires the Microsoft C++ Build Tools. Make sure to select the Desktop development with C++ workload when installing the tools.

You've installed the wasm32-wasip1 target

To ensure compatibility with the latest version of Rust, install the wasm32-wasip1 target.

Project

Anchor to Create the Discount FunctionCreate the Discount Function

To create a Discount Function, you'll use the Shopify CLI, which generates starter code for your Function.

  1. Navigate to your app's directory:

    Terminal

    cd directory
  2. Run the following command to create a new Discount Function:

    Terminal

    shopify app generate extension --template discount --name discount-function-rs
  3. Choose the language that you want to use. For this tutorial, select Rust.
Info

Steps 2-4 review the generated code. To proceed directly to deploying and testing your Discount Function, jump to Step 5.

Anchor to Review the Discount Function ConfigurationReview the Discount Function Configuration

The shopify.extension.toml file defines the Discount Function's metadata, targets, and build configuration.

The [[extensions]] section defines the Function metadata. This includes the Function's handle, name, description, and type. The name and description are displayed on the Discount page of your Shopify admin.

Info

Shopify provides localization tools, and you can use them to localize the name and description of Discount Functions. To learn more, refer to localizing your Shopify app.

The [[extensions.targeting]] sections define the Function targets. Each section includes a target, input_query, and export property.

The target property defines where the Function is applied. The Discount API has two run targets:

  • cart.lines.discounts.generate.run - The Function can apply discounts to cart lines and order subtotals.
  • cart.delivery-options.discounts.generate.run - The Function can apply discounts to shipping rates.

The input_query property is the path to the Function's input query file. This file defines the Function's input parameters.

The export property specifies the build entrypoint that will run for a specified target. This will usually be the function name of your main export.

The [extensions.build] section defines the build configuration for your Function. This includes the build command, the build path and a watch property which allows you to watch for changes to the Function. Refer to Shopify Functions configuration properties for more information.


Note

Depending on your app type, you may have to define the [extensions.ui] or [extensions.ui.paths] section.

Refer to Build a discounts UI with Admin UI Extensions or Build a discounts UI with Remix to learn more about building UIs to configure Functions.

Anchor to Review the input queries for your FunctionReview the input queries for your Function

Input queries are used to define the input that the Discount Function needs. The result of those queries will be given as input parameters to the export functions.

Anchor to [object Object], inputcart_lines_discounts_generate_run.graphql input

The result of this query is provided as input to the cart.lines.discounts.generate.run target. Refer to Discount API for more information about the input data available to your Function.

Anchor to [object Object], inputcart_delivery_options_discounts_generate_run.graphql input

The result of this query is provided as input to the cart.delivery-options.discounts.generate.run Function. Refer to Discount API for more information about the input data available to your Function.

Anchor to Review the logic of your FunctionReview the logic of your Function

To specify how a Discount Function should apply discounts, update its logic. This logic can make use of the input parameters provided to the Function, and should output discount operations.

Note

Your Function should only return operations for discountClasses that the discount applies to. For example, if the discount is configured to apply to PRODUCT and ORDER, but not SHIPPING, your Function should only return operations for PRODUCT and ORDER.

Anchor to Review your cart run Function logicReview your cart run Function logic

This is the entry point for cart line and order subtotal discount calculation logic. The name must match the export property in the [[extensions.targeting]] section of your Function's configuration and must output CartOperations.

In this example, the Function checks whether the discount applies to PRODUCT and ORDER and applies two discounts: 10% off the entire order subtotal, plus an additional 20% off the highest cart line subtotal.

Anchor to Review your delivery run Function logicReview your delivery run Function logic

This is the entry point for shipping rate discount calculation logic. The name must match the export property in the [[extensions.targeting]] section of your Function's configuration and must output DeliveryOperations.

In this example, the Function checks whether the discount applies to SHIPPING and reduces the first delivery group by 100%, offering free shipping.

Anchor to Update your app's access scopesUpdate your app's access scopes

You must request the write_discounts access scope to give your app the permissions that it needs to create and update discounts.

In shopify.app.toml, located in the root of your app, add the write_discounts scope to the access_scopes array.

Anchor to Deploy your app with new access scopesDeploy your app with new access scopes

  1. Deploy your updated configuration to Shopify:

    Terminal

    shopify app deploy
  2. Restart your app development server:

    Terminal

    shopify app dev
  3. Open or reinstall your app using the URL provided by Shopify CLI. To preview your extensions, press p in the terminal window where you started your app.

  4. Accept the new access scope permissions in your store.

Note

The development server automatically watches files that match the build.watch glob pattern. When it detects a change, it builds your Function and updates the Function extension's draft so that you can preview changes immediately.

Anchor to Create a discount in your storeCreate a discount in your store

In this step, you'll use GraphiQL, an in-browser tool for testing GraphQL, to create a discount that applies a line-item price adjustment, an order-wide percentage discount, and free shipping. Then you'll link this discount to the Function that you deployed in the previous step. GraphiQL is an in-browser tool for writing, validating, and testing GraphQL queries.

Info

You can also build a discount interface using Admin UI Extensions and configure your Functions using Metafields.

Anchor to Open the GraphiQL interface for the Shopify Admin APIOpen the GraphiQL interface for the Shopify Admin API

  1. Open the GraphiQL interface by pressing g in the terminal window where you started your app.
  2. On the GraphiQL interface, for API Version, select the latest stable release.

Anchor to Get the ID of your FunctionGet the ID of your Function

To get the ID of your Function, use the shopifyFunctions query. You'll use this ID to associate your Functions with the newly created discount.

The result contains a node with your Function's ID.

{
"app": {
"title": "your-app-name-here"
},
"apiType": "discounts",
"title": "discount-function-js",
"id": "YOUR_FUNCTION_ID_HERE"
}

To create a discount in your store, use the discountAutomaticAppCreate mutation.

  1. For functionId, provide the Function ID from the previous step.
  2. Add the discountClasses field to your mutation based on the business requirements.

You should receive a GraphQL response that includes the ID of the created discount. If the response includes any userErrors, then review them, check that your mutation and functionId are correct, and try the request again.

Troubleshooting

If you receive a Could not find Function error, then confirm the following:

  • The Function ID is correct.
  • You've installed the app on your development store.
  • Development store preview is enabled in the Partner Dashboard.
  • Your app has the write_discounts access scope.

Anchor to Test the Discount FunctionTest the Discount Function

In your Shopify admin, go to Discounts. You should now see the Cart line, Order, and Shipping discount that you created.

A list of all active discounts for the store.

Anchor to Deactivate other discountsDeactivate other discounts

Deactivate or delete all other discounts, to ensure that the Cart line, Order, and Shipping discount is the only active discount.

Open your development store and build a cart with a single item in it.

Anchor to Validate discount applicationValidate discount application

On the cart page, you should see that your Discount Function has applied a discount to a cart line and the order subtotal. Once you navigate to the checkout page and fill in your shipping address, you will see the discounts applied to the shipping rates.

A checkout summary that shows cart line, subtotal, and shipping discounts

Anchor to Review the Function executionReview the Function execution

  1. In the terminal where shopify app dev is running, review your Function executions.

    When testing Functions on development stores, the dev output shows Function executions, debug logs you've added, and a link to a local file containing full execution details.

  2. In a new terminal window, use the Shopify CLI command app function replay to replay a Function execution locally. This lets you debug your Function without triggering it again on Shopify.

    Terminal

    shopify app function replay
  3. Select the Function execution from the top of the list. Press q to quit when you are finished debugging.

Was this page helpful?