---
title: Rust for Functions
description: Learn about the support for Rust in Shopify Functions.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions
  md: >-
    https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md
api_type: functions
---

# Rust for Functions

You can write your functions in Rust. This guide describes the [`shopify_function`](https://crates.io/crates/shopify_function) Rust crate that Shopify provides to help developers build with Shopify Functions.

***

## Requirements

* The latest stable version of [Rust](https://www.rust-lang.org/tools/install), with the `wasm32-unknown-unknown` build target installed:

  ## Terminal

  ```terminal
  rustup target add wasm32-unknown-unknown
  ```

* Version 3.85.0 or higher of [Shopify CLI](https://shopify.dev/docs/api/shopify-cli#upgrade). Shopify recommends using the latest version.

* Version 2.0.0 or higher of the `shopify_function` crate. Functions that you generate with Shopify CLI use the latest version.

***

## How it works

The `shopify_function` Rust crate performs type generation, reduces boilerplate code, and makes it easier to test various function inputs. It includes the following components:

| Component | Description |
| - | - |
| `typegen` | A macro to enable struct generation from the Function API, based on the provided [GraphQL schema](https://shopify.dev/docs/api/functions/latest#graphql-schema-and-versioning) and [input query](https://shopify.dev/docs/api/functions/latest#input). |
| `shopify_function` | An attribute macro that marks the given function as the entrypoint for Shopify Functions, by:- Exporting a WebAssembly function with the same name as the Rust function. This name must match the target's `export` in the [function extension configuration](https://shopify.dev/docs/api/functions/configuration#properties).
- Reading the function's input and writing its output through the Shopify Functions WebAssembly API. |
| `Deserialize` | A derive macro that deserializes function input into your own structs, such as a JSON metafield configuration. It supports the `rename_all`, `rename`, and `default` attributes through `#[shopify_function(...)]`. |
| `log!` | A macro that writes to your function's logs. Use it instead of `eprintln!`. |
| `run_function_with_input` | A utility for unit testing that enables you to add new tests based on a given JSON input string. |

***

## Viewing the generated types

To preview the types generated by the `typegen` macro, use the [`cargo doc`](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) command.

## Terminal

```terminal
cargo doc --open
```

You can also use the [cargo-expand](https://github.com/dtolnay/cargo-expand) crate to view the generated source:

## Terminal

```terminal
cargo install cargo-expand
cargo expand
```

***

## Development tools

To make development easier, install the [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) VSCode extension for:

* Code completion
* Go to definition
* Real-time error checking
* Type information on hover

***

## Example implementations

Explore example implementations using the `shopify_function` Rust crate.

[Rust Shopify Function example\
\
](https://github.com/Shopify/shopify-function-rust/tree/main/example_with_targets)

[Explore an example of how to use the `shopify_function` crate to implement a Shopify Function in Rust.](https://github.com/Shopify/shopify-function-rust/tree/main/example_with_targets)

***

## Binary size tips

The compiled Wasm file for a Shopify Function must be under 256 kB. Here are a few tips to keep binary size small when using Rust:

* Update the [`shopify_function`](https://crates.io/crates/shopify_function) crate to the latest version.

* Keep the release profile settings from the function templates in your `Cargo.toml`. They enable link-time optimization, optimize for size, and strip symbols:

  ## Cargo.toml

  ```toml
  [profile.release]
  lto = true
  opt-level = "z"
  strip = true
  ```

* Keep the `wasm_opt` [configuration property](https://shopify.dev/docs/api/functions/latest#configuration) enabled. Shopify CLI runs `wasm-opt` on your module by default, which further reduces its size.

* For regular expressions, use the [regex\_lite](https://docs.rs/regex-lite/latest/regex_lite/) crate.

* Follow tips and documentation in the [johnthagen/min-sized-rust](https://github.com/johnthagen/min-sized-rust) GitHub repository.

* Use `to_ascii_uppercase` and `to_ascii_lowercase` when possible to avoid pulling in Unicode tables, unless needed.

* Only query for data you need.

  Code generation happens for all types and fields included in the input queries (for example, `run.graphql`). Review and remove any unused parts of the queries.

* Keep JSON metafields that require deserialization as small as possible.

  Code generated for deserialization increases the binary size. The smaller the metafield is, the less code needs to be generated.

To reduce the number of instructions that your function executes, refer to [Optimize instruction counts](https://shopify.dev/docs/apps/build/functions/optimize-instruction-counts).

***

## Updating existing function to using shopify\_​function 2.​0.​0 and higher

If you are using a version less than `1.0.0`, you should update to version `1.1.1` as outlined below before following these steps.

1. [Update to the latest](https://shopify.dev/docs/api/shopify-cli#installation) Shopify CLI version. Version 2.0.0 of the crate requires Shopify CLI 3.85.0 or higher.

2. Update the `shopify_function` dependency in your `Cargo.toml` to the latest version:

   ## Cargo.toml

   ```toml
   [dependencies]
   shopify_function = "2.2.0"
   ```

3. Install the `wasm32-unknown-unknown` build target using [`rustup target`](https://rust-lang.github.io/rustup/cross-compilation.html):

   ## Terminal

   ```terminal
   rustup target add wasm32-unknown-unknown
   ```

4. Update your build `command` and `path` in the `[extensions.build]` section of your [`shopify.extension.toml`](https://shopify.dev/docs/api/functions/latest#configuration) to use `wasm32-unknown-unknown` instead of `wasm32-wasip1`. Replace `RUST-PACKAGE-NAME` with the `name` from your `Cargo.toml`:

   ## shopify.extension.toml

   ```toml
   [extensions.build]
   command = "cargo build --target=wasm32-unknown-unknown --release"
   path = "target/wasm32-unknown-unknown/release/[RUST-PACKAGE-NAME].wasm"
   ```

5. Throughout all of your source files, update any references to `eprintln!` to use `log!` instead.

   ```rust
   #[shopify_function]
   fn run(input: schema::run::Input) -> Result<schema::FunctionRunResult> {
     log!("This will be logged");
     todo!();
   }
   ```

6. Throughout all of your source files, update any references to `process::exit(1)` to use `process::abort()` instead.

   ```rust
   #[shopify_function]
   fn run(input: schema::run::Input) -> Result<schema::FunctionRunResult> {
     log!("Please invoke a named export.");
     process::abort();
   }
   ```

***

## Updating existing function to using shopify\_​function 1.​0.​0 and higher

If your function uses a version of the `shopify_function` crate below 1.0.0, then follow these steps to update it to version 1.0.0 and higher. After that, [update to version 2.0.0 and higher](#updating-existing-function-to-using-shopify_function-200-and-higher).

1. In `main.rs`, add imports for `shopify_function`.

   ```rust
   use shopify_function::prelude::*;
   use shopify_function::Result;
   ```

2. In `main.rs`, add type generation, right under your imports. Remove any references to the `generate_types!` macro.

   ```rust
   #[typegen("schema.graphql")]
   pub mod schema {
     #[query("src/run.graphql")]
     pub mod run {}
   }
   ```

   If your Function has multiple targets each with their own input query, add a nested module for each. For example:

   ```rust
   #[typegen("schema.graphql")]
   pub mod schema {
     #[query("src/fetch.graphql")]
     pub mod fetch {}


     #[query("src/run.graphql")]
     pub mod run {}
   }
   ```

3. In `main.rs`, ensure that you have a `main` function that returns an error indicating to invoke a named export:

   ```rust
   fn main() {
     log!("Please invoke a named export.");
     std::process::abort();
   }
   ```

4. If you have an input query to retrieve a JSON metafield value in your `run.graphql` file, for example:

   ## Rust input query

   src/run.graphql

   ```graphql
   query Input {
       deliveryCustomization {
           metafield(namespace: "delivery-customization", key: "function-configuration") {
             jsonValue
           }
       }
   }
   ```

   You can deserialize the `jsonValue` directly into an object you define in your `run.rs` file and annotate with `#[shopify_function(rename_all = "camelCase")]` and `#[derive(Deserialize)]` as shown below:

   ## Rust

   src/run.rs

   ```rust
   #[derive(Deserialize)]
   #[shopify_function(rename_all = "camelCase")]
   pub struct DeliveryConfiguration {
       state_province_code: String,
       message: String,
   }
   ```

   Finally, use `custom_scalar_overrides` to link the `jsonValue` with its object definition in your `main.rs` file as shown below:

   ## Rust

   src/main.rs

   ```rust
   #[typegen("schema.graphql")]
   mod schema {
       #[query("src/run.graphql",
           custom_scalar_overrides = {
               "Input.deliveryCustomization.metafield.jsonValue" => super::run::DeliveryConfiguration,
           }
       )]
       pub mod run {}
   }
   ```

5. Ensure your source file that has the function logic defined, includes the following imports.

   ```text
   use shopify_function::prelude::*;
   use shopify_function::Result;
   use super::schema;
   ```

   typically this is in `run.rs` or `fetch.rs`

6. Throughout all of your source files, replace any references to `#[shopify_function_target]` with the `#[shopify_function]` macro, and change its return type. Typically, this is located in a file with a name equal to the target, e.g. `run.rs`.

   ```rust
   #[shopify_function]
   fn run(input: schema::run::Input) -> Result<schema::FunctionRunResult> {
   ```

7. Update the types and fields utilized in the function to the new, auto-generated structs. For example:

   | Old | New |
   | - | - |
   | `input::ResponseData` | `schema::run::Input` |
   | `input::InputDiscountNodeMetafield` | `schema::run::input::discount_node::Metafield` |
   | `input::InputDiscountNode` | `schema::run::input::DiscountNode` |
   | `output::FunctionRunResult` | `schema::FunctionRunResult` |
   | `output::DiscountApplicationStrategy::FIRST` | `schema::DiscountApplicationStrategy::First` |

***

## Updating to Rust 1.​84 and higher

Previously, we encouraged the use of `cargo-wasi` as a way to build and optimize your Rust functions. However, as of Rust version 1.84, the `wasm32-wasi` build target used by `cargo-wasi` was removed.

If your function still builds with `cargo-wasi` or the `wasm32-wasi` target, then update it to version 2.0.0 or higher of the `shopify_function` crate by following the steps in [Updating existing function to using shopify\_function 2.0.0 and higher](#updating-existing-function-to-using-shopify_function-200-and-higher). Version 2.0.0 and higher builds with the `wasm32-unknown-unknown` target, and works with the latest stable version of Rust.

You can also remove the deprecated `wasm32-wasi` build target using [`rustup target`](https://rust-lang.github.io/rustup/cross-compilation.html):

## Terminal

```terminal
rustup target remove wasm32-wasi
```

**Note:**

In addition to building your Rust function for WebAssembly, the `cargo-wasi` crate also optimized the size of your binary using the [Binaryen](https://github.com/WebAssembly/binaryen) toolchain. Shopify CLI optimizes your module by default. You can configure this behavior with the `wasm_opt` [configuration property](https://shopify.dev/docs/api/functions/latest#configuration).

***

## Migrating from Java​Script

Migrating your JavaScript Shopify Function to Rust can significantly improve performance and help you stay within platform fuel limits. Rust compiles directly to WebAssembly, resulting in more efficient execution compared to JavaScript. To measure and reduce instruction counts before and after migration, refer to [Optimize instruction counts](https://shopify.dev/docs/apps/build/functions/optimize-instruction-counts).

The safest way to migrate is to add your Rust code alongside your JavaScript code in the same function extension, and then use `shopify.extension.toml` to choose which language to build. Your extension, its `uid`, and its configuration stay the same. Only the language and the compiled WebAssembly module change, so merchants don't need to do anything, and you can switch back to JavaScript at any time.

### Add Rust to your Java​Script function

1. Update your JavaScript function to version 2.0.0 or higher of the [`@shopify/shopify_function`](https://npm.im/@shopify/shopify_function) package. While your JavaScript entry file is in `src/`, Shopify CLI picks the local function runner based on this package's version. Earlier versions use a function runner that can't run modules built with version 2.0.0 or higher of the `shopify_function` Rust crate, so `app function run`, `app function replay`, and profiling fail for your Rust build. Run the following command in your function's directory, and then confirm that your JavaScript function still builds and passes its tests:

   ## Terminal

   ```terminal
   npm install @shopify/shopify_function@^2.0.0
   ```

2. Install the `wasm32-unknown-unknown` build target using [`rustup target`](https://rust-lang.github.io/rustup/cross-compilation.html):

   ## Terminal

   ```terminal
   rustup target add wasm32-unknown-unknown
   ```

3. Generate a temporary Rust function to use as a starting point:

   ## Terminal

   ```terminal
   shopify app generate extension
   ```

   When prompted, choose the same function type as your existing JavaScript function, and select `Rust` as the language.

4. Copy the `Cargo.toml` file from the temporary function into your JavaScript function's directory.

5. Copy the `.rs` files from the temporary function's `src/` directory into your JavaScript function's `src/` directory. Your JavaScript files stay where they are, and both languages share the same `schema.graphql` file and input queries.

6. Delete the temporary function's directory, so that it isn't deployed with your app.

7. Add `target/` to your function's `.gitignore` file to exclude Rust build output.

8. Update your input queries for Rust type generation. Add `__typename` to any fragments on interfaces or unions. This change doesn't affect your JavaScript code:

   ## src/cart\_lines\_discounts\_generate\_run.graphql

   ```graphql
   query CartInput {
     cart {
       lines {
         merchandise {
           __typename
           ... on ProductVariant {
             id
           }
         }
       }
     }
   }
   ```

   You don't need to rename your queries. The Rust input type takes its name from the query's operation name, so `query CartInput` generates a `CartInput` type. Update the copied Rust code to use your type names, and make sure that the `#[query]` paths in `main.rs` match your input query files.

9. If your function reads its configuration from a JSON metafield, then deserialize the metafield directly into a Rust struct. Your JavaScript function reads the parsed object from `jsonValue`. In Rust, you define a struct for the configuration and tell the `typegen` macro to use it as the type of the `jsonValue` field.

   For example, the following input query reads a JSON configuration metafield on the discount:

   ## src/cart\_lines\_discounts\_generate\_run.graphql

   ```graphql
   query CartInput {
     discount {
       metafield(namespace: "$app:my-discount", key: "function-configuration") {
         jsonValue
       }
     }
   }
   ```

   Define a struct that matches your configuration JSON. The `Deserialize` derive macro from the `shopify_function` crate reads the value directly from the function input. Use `rename_all = "camelCase"` to map the JSON keys to `snake_case` field names, and `default` for optional fields:

   ## src/cart\_lines\_discounts\_generate\_run.rs

   ```rust
   use shopify_function::prelude::*;


   #[derive(Deserialize)]
   #[shopify_function(rename_all = "camelCase")]
   pub struct Configuration {
       pub discount_percentage: f64,
       #[shopify_function(default)]
       pub excluded_product_ids: Vec<String>,
   }
   ```

   In `main.rs`, use the `custom_scalar_overrides` argument of the `#[query]` attribute to map the `jsonValue` field to your struct. The key is the path to the field, starting with the query's operation name. A type path that doesn't start with `::` is relative to the `schema` module, so use `super::` to reach your target's module:

   ## src/main.rs

   ```rust
   #[typegen("schema.graphql")]
   pub mod schema {
       #[query(
           "src/cart_lines_discounts_generate_run.graphql",
           custom_scalar_overrides = {
               "CartInput.discount.metafield.jsonValue" => super::cart_lines_discounts_generate_run::Configuration,
           }
       )]
       pub mod cart_lines_discounts_generate_run {}
   }
   ```

   Your function then receives the configuration as a typed struct, with no JSON parsing in your code:

   ## src/cart\_lines\_discounts\_generate\_run.rs

   ```rust
   let Some(configuration) = input.discount().metafield().map(|metafield| metafield.json_value()) else {
       return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
   };
   let percentage = configuration.discount_percentage;
   ```

10. Port your JavaScript logic to the `.rs` files.

### Switch between Java​Script and Rust

The `[extensions.build]` section and each target's `export` in `shopify.extension.toml` determine which language Shopify CLI builds. Rust exports use the name of the Rust function marked with `#[shopify_function]`, which is usually in `snake_case`, so the `export` values differ between languages.

To build the Rust version, update the `export` for each target and the `[extensions.build]` section. Keep your JavaScript values as comments. To switch back, comment out the Rust lines, including `watch`, and uncomment the JavaScript lines. Replace `RUST-PACKAGE-NAME` with the `name` from your `Cargo.toml`:

## shopify.extension.toml

```toml
[[extensions.targeting]]
  target = "cart.lines.discounts.generate.run"
  input_query = "src/cart_lines_discounts_generate_run.graphql"
  # JavaScript:
  # export = "cart-lines-discounts-generate-run"
  # Rust:
  export = "cart_lines_discounts_generate_run"


  [extensions.build]
  # JavaScript:
  # command = ""
  # path = "dist/function.wasm"
  # Rust:
  command = "cargo build --target=wasm32-unknown-unknown --release"
  path = "target/wasm32-unknown-unknown/release/[RUST-PACKAGE-NAME].wasm"
  watch = ["src/**/*.rs"]
```

**Note:**

While your JavaScript entry file, such as `src/index.js`, is in the `src/` directory, Shopify CLI treats the extension as a JavaScript function in some places. For example, `app function run --profile` warns that the profile won't contain function names, even when your Rust build keeps them.

### Validate and deploy the migration

1. Update your integration tests so that the same fixtures work with both languages. Each fixture's `export` value records the JavaScript export name, which the Rust module doesn't have. In `tests/default.test.js`, pass the export from `shopify.extension.toml` to `runFunction` instead:

   ## tests/default.test.js

   ```js
   const runResult = await runFunction(
     { ...fixture, export: targeting[fixture.target].export ?? fixture.export },
     functionRunnerPath,
     wasmPath,
     targetInputQueryPath,
     schemaPath,
   );
   ```

2. Run your function's integration tests with the JavaScript configuration, and then again with the Rust configuration. Both versions should produce the expected output for every fixture. You can also compare instruction counts between the two runs:

   ## Terminal

   ```terminal
   npm test
   ```

3. Deploy to a dev store and verify that the function works as expected.

4. Deploy your app. Every store that uses your function runs the Rust version, because the extension itself hasn't changed.

5. If you find an issue, then switch `shopify.extension.toml` back to the JavaScript configuration and deploy again.

6. When you're confident in the Rust version, remove your JavaScript source files from `src/`.

***

## Next steps

* Explore the [reference documentation](https://docs.rs/shopify_function/latest/shopify_function/) for the `shopify_function` Rust crate.

***
