--- 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 --- ExpandOn this page * [How it works](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#how-it-works) * [Viewing the generated types](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#viewing-the-generated-types) * [Development tools](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#development-tools) * [Example implementations](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#example-implementations) * [Binary size tips](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#binary-size-tips) * [Updating existing function to using shopify\_​function 2.​0.​0 and higher](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#updating-existing-function-to-using-shopify_function-200-and-higher) * [Updating existing function to using shopify\_​function 1.​0.​0 and higher](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#updating-existing-function-to-using-shopify_function-100-and-higher) * [Updating to Rust 1.​84 and higher](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#updating-to-rust-184-and-higher) * [Migrating from Java​Script](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#migrating-from-javascript) * [Next steps](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#next-steps) # 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. *** ## 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/current#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 specified name, which must match the target export in the [function extension configuration](https://shopify.dev/docs/api/functions/configuration#properties). - Providing an efficient API to manage the function's input and output. | | `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 `shopify_function` Rust crate, 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 --doc ``` *** ## 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 Note The generated `.output.graphql` files are used for output type generation purposes. You can add these files to your `.gitignore` file. *** ## 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) [Rust Shopify Function example for earlier versions\ \ ](https://github.com/Shopify/shopify-function-rust/tree/main/example) [Explore an example of how to use the `shopify_function` crate to implement a Shopify Function in Rust compatible with API versions 2023-07 and earlier.](https://github.com/Shopify/shopify-function-rust/tree/main/example) *** ## Binary size tips Shopify Functions compiled Wasm file 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. * 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 [`wasm-snip`](https://github.com/rustwasm/wasm-snip) to remove the panicking code, then `wasm-opt` to strip debug information. For example: ```text # Change this line: export WASM_PATH=target/wasm32-unknown-unknown/release/your-function-name.wasm RUSTFLAGS="-C strip=none" cargo build --target=wasm32-unknown-unknown --release \ && wasm-snip --snip-rust-panicking-code $WASM_PATH \ | wasm-opt -O3 --enable-bulk-memory --strip-debug -o function.no-panic.wasm - ``` * 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. * Bring your own types and deserializers. Instead of using the generated structs from the `shopify_function_macro` crate, write the appropriate struct definitions and derive the deserializers using [`mini_serde`](https://github.com/dtolnay/miniserde). The structs from `shopify_function_macro` can be used as a starting point, see them with [`cargo expand`](https://github.com/dtolnay/cargo-expand). Alternative serializers are generally less efficient than serde, make sure to benchmark the instruction count when going down this path. * Updating the `shopify_function` crate in your function to version `1.0.0` and above as outlined below. *** ## 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. 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. 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" ``` 4. 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 { log!("This will be logged"); todo!(); } ``` 5. 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 { log!("Please invoke a named export."); process::abort(); } ``` *** ## Updating existing function to using shopify\_​function 1.​0.​0 and higher Migrate your function to the latest `shopify_function` crate for potential speedups and smaller binary sizes. Follow these steps: 1. In `main.rs`, add imports for `shopify_function`. ```rust use shopify_function::prelude::*; ``` 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!("Invoke a named import"); 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 { ``` 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 WebAssembly build target used by `cargo-wasi` was removed. To migrate an existing Rust function to Rust version 1.84 or higher, complete the following steps: 1. [Update to the latest](https://shopify.dev/docs/api/shopify-cli#installation) Shopify CLI version. 2. 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 ``` 3. Update your Rust version using [`rustup update`](https://rust-lang.github.io/rustup/basics.html): ## Terminal ```terminal rustup update stable ``` 4. Install the new `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 ``` 5. Update your build `command` and `path` in the `[extensions.build]` section of your [`shopify.extension.toml`](https://shopify.dev/docs/api/functions/latest#configuration). 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" ``` These changes are compatible with Rust 1.78 and higher. 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 will now optimize your module by default. You can configure this behavior via 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. ### Java​Script migration steps 1. Generate a new function using Shopify CLI: ## Terminal ```terminal shopify app generate extension ``` 2. When prompted: * Choose the same function type as your existing JavaScript function * Name it the same as your current function but append `-rs` (e.g., if your current function is `product-discount`, name it `product-discount-rs`) * Select `Rust` as the language 3. Copy your existing GraphQL query, making these adjustments to support the Rust code generation: * Copy your `run.graphql` from your JavaScript function to the new Rust function's `src` directory * Rename the query from `RunInput` to `Input` * Add `__typename` to any fragments on interfaces or unions: ## src/run.graphql ```graphql # Before (JavaScript): # query RunInput { # cart { # lines { # merchandise { # ... on ProductVariant { # id # } # } # } # } # } # After (Rust): query Input { cart { lines { merchandise { __typename ... on ProductVariant { id } } } } } ``` 4. Port your JavaScript logic to the generated `src/run.rs` file ### Reusing extension UIDs By reusing the extension UID from your JavaScript function, you can seamlessly replace the existing function on the server. The `uid` is the unique identifier that determines which function gets updated. This means all existing instances of your function will automatically use the new Rust implementation without any changes required on the merchant's side. Migration steps: 1. Copy the existing `uid` and `handle` from your JavaScript function's `shopify.extension.toml`: ## extensions/your-function/shopify.extension.toml ```toml # JavaScript function's configuration name = "your-function" handle = "your-existing-handle" uid = "your-existing-uid" # The uid is the critical identifier ``` 2. Update your new Rust function's configuration with the copied `uid` and `handle`: ## extensions/your-function-rs/shopify.extension.toml ```toml # Rust function's configuration name = "your-function-rs" handle = "your-existing-handle" uid = "your-existing-uid" # The uid ensures the right function gets updated ``` 3. Disable the JavaScript function by renaming its configuration file: ## Terminal ```terminal mv extensions/your-function/shopify.extension.toml extensions/your-function/shopify.extension.disabled.toml ``` Warning If you deploy both functions, they will both appear in the merchant admin, which may cause confusion. Always ensure you've disabled the JavaScript function before deploying the Rust version. ### Validating the migration Before deploying to production: 1. Test the function locally: ## Terminal ```terminal shopify app function run --input input.json ``` 2. Deploy to a dev store and verify the function works as expected 3. Confirm only one function appears in the merchant admin 4. If everything works correctly, you can safely delete the JavaScript function directory *** ## Next steps * Explore the [reference documentation](https://docs.rs/shopify_function/latest/shopify_function/) for the `shopify_function` Rust crate. *** * [How it works](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#how-it-works) * [Viewing the generated types](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#viewing-the-generated-types) * [Development tools](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#development-tools) * [Example implementations](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#example-implementations) * [Binary size tips](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#binary-size-tips) * [Updating existing function to using shopify\_​function 2.​0.​0 and higher](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#updating-existing-function-to-using-shopify_function-200-and-higher) * [Updating existing function to using shopify\_​function 1.​0.​0 and higher](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#updating-existing-function-to-using-shopify_function-100-and-higher) * [Updating to Rust 1.​84 and higher](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#updating-to-rust-184-and-higher) * [Migrating from Java​Script](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#migrating-from-javascript) * [Next steps](https://shopify.dev/docs/apps/build/functions/programming-languages/rust-for-functions.md#next-steps)