Skip to content
Back to skills

2553 Functions 81f7b794

ASecurity

Shopify Functions replace Scripts as the way to customise backend logic. They run in a WebAssembly sandbox with strict performance guarantees.

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 31, 2026
developmentjavascriptrustgojavarubybashnodetestinggitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add tools-only/X-Skills --skill 2553-functions_81f7b794 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2553 Functions 81f7b794?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2553 Functions 81f7b794
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2553-functions-81f7b794/badge)](https://www.skillsdirectory.com/skills/tools-only-2553-functions-81f7b794)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Shopify Functions Reference

Shopify Functions replace Scripts as the way to customise backend logic. They run in a WebAssembly sandbox with strict performance guarantees.

## Overview

| Item | Value |
|------|-------|
| Runtime | WebAssembly (Wasm) |
| Languages | Rust (recommended), JavaScript (via Javy) |
| Execution limit | 11ms instruction count limit |
| Memory limit | 64 KB linear memory |
| Input/Output | JSON (stdin/stdout) |
| API version | 2026-01 |

## Function Types

| Type | Purpose | Replaces |
|------|---------|----------|
| `product_discounts` | Automatic product discounts | Shopify Scripts (line item) |
| `order_discounts` | Order-level discounts | Shopify Scripts (order) |
| `shipping_discounts` | Shipping rate discounts | Shopify Scripts (shipping) |
| `payment_customization` | Hide/reorder payment methods | Shopify Scripts |
| `delivery_customization` | Hide/reorder/rename delivery options | Shopify Scripts |
| `cart_transform` | Merge/expand/update cart lines | New |
| `fulfillment_constraints` | Constrain fulfillment locations | New |
| `order_routing_location_rule` | Custom order routing | New |
| `cart_checkout_validation` | Validate cart at checkout | New |

## Getting Started

### Create a Function

```bash
# Generate a new function extension
shopify app generate extension --template discount_function_rust
# or
shopify app generate extension --template discount_function_javascript

# Structure created:
extensions/my-discount/
├── src/
│   ├── main.rs          # Rust: function logic
│   └── run.graphql      # Input query
├── Cargo.toml           # Rust dependencies
├── shopify.extension.toml
└── schema.graphql       # Generated API schema
```

### Input Query (run.graphql)

Define what data your function receives:

```graphql
query RunInput {
  cart {
    lines {
      quantity
      merchandise {
        ... on ProductVariant {
          id
          product {
            id
            hasAnyTag(tags: ["VIP"])
          }
        }
      }
      cost {
        amountPerQuantity {
          amount
          currencyCode
        }
      }
    }
  }
  discountNode {
    metafield(namespace: "discount", key: "config") {
      value
    }
  }
}
```

### Rust Implementation

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

#[shopify_function_target(rename = "function")]
fn function(input: input::ResponseData) -> Result<output::FunctionRunResult> {
    let config: serde_json::Value = serde_json::from_str(
        input.discount_node.metafield
            .as_ref()
            .map(|m| m.value.as_str())
            .unwrap_or("{}"),
    )?;

    let percentage = config.get("percentage")
        .and_then(|v| v.as_f64())
        .unwrap_or(0.0);

    let targets: Vec<output::Target> = input
        .cart
        .lines
        .iter()
        .filter_map(|line| {
            let variant = match &line.merchandise {
                input::InputCartLinesMerchandise::ProductVariant(v) => v,
                _ => return None,
            };

            if variant.product.has_any_tag {
                Some(output::Target::ProductVariant(
                    output::ProductVariantTarget {
                        id: variant.id.clone(),
                        quantity: None,
                    },
                ))
            } else {
                None
            }
        })
        .collect();

    if targets.is_empty() {
        return Ok(output::FunctionRunResult {
            discounts: vec![],
            discount_application_strategy:
                output::DiscountApplicationStrategy::FIRST,
        });
    }

    Ok(output::FunctionRunResult {
        discounts: vec![output::Discount {
            message: Some(format!("{}% VIP discount", percentage)),
            targets,
            value: output::Value::Percentage(output::Percentage {
                value: percentage.to_string(),
            }),
        }],
        discount_application_strategy:
            output::DiscountApplicationStrategy::FIRST,
    })
}
```

### JavaScript Implementation

```javascript
// src/run.js
export function run(input) {
  const config = JSON.parse(
    input?.discountNode?.metafield?.value ?? "{}"
  );

  const percentage = parseFloat(config.percentage) || 0;

  const targets = input.cart.lines
    .filter((line) => {
      return line.merchandise?.__typename === "ProductVariant"
        && line.merchandise.product.hasAnyTag;
    })
    .map((line) => ({
      productVariant: { id: line.merchandise.id },
    }));

  if (targets.length === 0) {
    return { discounts: [], discountApplicationStrategy: "FIRST" };
  }

  return {
    discounts: [
      {
        message: `${percentage}% VIP discount`,
        targets,
        value: {
          percentage: { value: percentage.toString() },
        },
      },
    ],
    discountApplicationStrategy: "FIRST",
  };
}
```

## Configuration

### shopify.extension.toml

```toml
api_version = "2026-01"

[[extensions]]
name = "VIP Discount"
handle = "vip-discount"
type = "function"

  [extensions.build]
  command = "cargo wasi build --release"
  path = "target/wasm32-wasi/release/vip-discount.wasm"

  # For JavaScript:
  # command = "npx javy compile src/run.js -o dist/function.wasm"
  # path = "dist/function.wasm"

  [extensions.targeting]
  target = "purchase.product-discount.run"

  [extensions.ui]
  handle = "vip-discount-ui"

  [extensions.input.variables]
  namespace = "discount"
  key = "config"
```

## Testing

### Unit tests (Rust)

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_no_discount_without_tag() {
        let input = input::ResponseData {
            cart: input::InputCart {
                lines: vec![/* line without VIP tag */],
            },
            discount_node: input::InputDiscountNode {
                metafield: Some(input::InputDiscountNodeMetafield {
                    value: r#"{"percentage": 10}"#.to_string(),
                }),
            },
        };

        let result = function(input).unwrap();
        assert!(result.discounts.is_empty());
    }
}
```

### Local testing

```bash
# Test with sample input
shopify app function run --path extensions/my-discount

# Build and preview
shopify app dev
```

## Deployment

```bash
# Deploy function with app
shopify app deploy

# Functions are versioned with the app
# Each deploy creates a new function version
```

## Migration from Scripts

| Scripts | Functions |
|---------|-----------|
| Ruby-like DSL | Rust or JavaScript (Wasm) |
| Online Store only | All channels (POS, B2B, headless) |
| Limited to 3 types | 10+ function types |
| No version control | Git-based, CI/CD ready |
| Script Editor app | Shopify CLI |
| Shopify-hosted | Developer-hosted logic |

**Migration steps:**

1. Identify Scripts in use (Settings > Apps > Script Editor)
2. Map each Script to a Function type (see table above)
3. Rewrite logic in Rust or JavaScript
4. Test with `shopify app function run`
5. Deploy and activate via Shopify admin
6. Disable old Scripts

## Performance Guidelines

- Functions must complete within the instruction count limit (~11ms equivalent)
- Minimise allocations - reuse buffers where possible
- Avoid complex string operations in hot paths
- Rust compiles to smaller, faster Wasm than JavaScript
- Use `cargo wasi build --release` for optimised builds
- Profile with `shopify app function run --export-timing`

## Best Practices

1. **Use Rust for production** - smaller binaries, faster execution
2. **Use JavaScript for prototyping** - faster iteration, familiar syntax
3. **Keep input queries minimal** - request only the fields you need
4. **Store configuration in metafields** - avoid hardcoded values
5. **Test edge cases** - empty carts, missing metafields, zero quantities
6. **Version your functions** - use semantic versioning with app deploys
7. **Monitor execution** - check function logs in Partner Dashboard

Files in this skill

  • README.md1 KB
  • skill.md7.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…