Documentation Index
Fetch the complete documentation index at: https://docs.synapsebuilder.org/llms.txt
Use this file to discover all available pages before exploring further.
Shopify Rust Functions Guide
Overview
Shopify Functions run on Shopify’s infrastructure as WebAssembly (WASM) modules. They must be written in Rust using the shopify_function crate.
Function Structure
Basic Discount Function
use shopify_function::prelude::*;
use shopify_function::Result;
// Input/Output types generated from GraphQL schema
use super::input::*;
use super::output::*;
#[shopify_function]
fn run(input: input::ResponseData) -> Result<output::FunctionResult> {
// Parse configuration from metafield
let config = parse_configuration(&input)?;
// Business logic
let discount_percentage = config.percentage.unwrap_or(10.0);
let minimum_amount = config.minimum_amount.unwrap_or(0.0);
// Check cart total
let cart_total = input.cart.cost.subtotal_amount.amount;
if cart_total < minimum_amount {
// No discount - return empty result
return Ok(output::FunctionResult {
discounts: vec![],
discount_application_strategy: output::DiscountApplicationStrategy::FIRST,
});
}
// Apply discount
let targets = vec![output::Target {
product_variant: Some(output::ProductVariantTarget {
id: input.cart.lines[0].merchandise.id.clone(),
quantity: None,
}),
}];
Ok(output::FunctionResult {
discounts: vec![output::Discount {
message: Some(format!("{}% off", discount_percentage)),
targets,
value: output::Value {
percentage: Some(output::Percentage {
value: discount_percentage.to_string(),
}),
fixed_amount: None,
},
}],
discount_application_strategy: output::DiscountApplicationStrategy::FIRST,
})
}
// Helper to parse configuration JSON from metafield
fn parse_configuration(input: &input::ResponseData) -> Result<Configuration> {
let config_value = input
.discount_node
.metafield
.as_ref()
.and_then(|m| m.value.as_ref())
.ok_or("Missing configuration")?;
serde_json::from_str(config_value)
.map_err(|_| "Invalid configuration JSON".into())
}
#[derive(serde::Deserialize)]
struct Configuration {
percentage: Option<f64>,
minimum_amount: Option<f64>,
}
Function Types
1. Product Discount Function
Target: purchase.product-discount.run
Use Case: Apply discounts to specific products/variants
2. Order Discount Function
Target: purchase.order-discount.run
Use Case: Apply discounts to entire order
3. Shipping Discount Function
Target: purchase.shipping-discount.run
Use Case: Modify shipping rates
4. Payment Customization
Target: purchase.payment-customization.run
Use Case: Hide/rename payment methods
5. Delivery Customization
Target: purchase.delivery-customization.run
Use Case: Modify delivery options
6. Cart/Checkout Validation
Target: purchase.validation.run
Use Case: Block checkout based on conditions
query RunInput {
discountNode {
metafield(namespace: "$app:function-configuration", key: "function-configuration") {
value
}
}
cart {
cost {
subtotalAmount {
amount
}
}
lines {
merchandise {
... on ProductVariant {
id
}
}
}
}
}
query RunInput {
cart {
cost {
subtotalAmount {
amount
}
}
}
paymentMethods {
id
name
}
}
Cargo.toml Template
[package]
name = "function_name"
version = "0.1.0"
edition = "2021"
[dependencies]
shopify_function = "1.3.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[profile.release]
lto = true
opt-level = "z"
strip = true
Extension TOML Template
api_version = "2025-01"
[[extensions]]
name = "function-name"
handle = "function-name"
type = "function"
description = "Function description"
[[extensions.targeting]]
target = "purchase.product-discount.run"
input_query = "src/run.graphql"
export = "run"
Common Patterns
1. Percentage Discount
value: output::Value {
percentage: Some(output::Percentage {
value: "10.0".to_string(),
}),
fixed_amount: None,
}
2. Fixed Amount Discount
value: output::Value {
percentage: None,
fixed_amount: Some(output::FixedAmount {
amount: "5.00".to_string(),
}),
}
3. Conditional Logic
if cart_total > 100.0 {
// Apply 15% discount
} else if cart_total > 50.0 {
// Apply 10% discount
} else {
// No discount
}
4. Customer Segment Checking
let is_vip = input.customer
.and_then(|c| c.tags)
.map(|tags| tags.contains(&"VIP".to_string()))
.unwrap_or(false);
Deployment Flow
- Generate Rust Code: AI generates
src/run.rs
- Create GraphQL Query: Define input schema in
src/run.graphql
- Add Cargo.toml: Rust package configuration
- GitHub Actions:
- Installs Rust toolchain
- Compiles to
wasm32-wasi target
- Optimizes with
wasm-opt
- Shopify CLI: Deploys WASM module to Shopify
Testing Locally
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add WASM target
rustup target add wasm32-wasi
# Build function
cd extensions/your-function
cargo build --target wasm32-wasi --release
# Test with Shopify CLI
shopify app function run
Best Practices
- Keep Functions Fast: < 10ms execution time
- Handle Missing Data: Use
.unwrap_or() and error handling
- Validate Input: Check configuration and cart data
- Clear Messages: Provide descriptive discount messages
- Test Edge Cases: Empty cart, zero prices, missing fields
Resources