Loading tutorials…
Loading tutorials…
Most Plus brands migrated Scripts to Functions in a rush before the deprecation deadline. Now subtle bugs are surfacing: discounts not stacking, shipping rates wrong on edge cases, Functions silently failing. Here's the diagnostic sequence.
Who this is forShopify Plus brands who migrated from Scripts to Functions and are now seeing checkout bugs, discount errors, or unexplained revenue dips. Especially relevant if migration was rushed before Shopify's deprecation.
What you'll need
Step 1
Before debugging, document what each Function is supposed to do. You cannot fix what you don't understand.
Shopify Admin → Apps → list every app that's a Functions app. These are typically named 'checkout-functions,' 'discount-functions,' or similar.
For each Functions app, list each extension inside it. Get the source code (git repo, original dev's machine, or 'export source' via Shopify CLI).
For each Function: what type is it (Product Discount, Order Discount, Shipping Discount, Delivery Customization, Payment Customization)? What's the business purpose? What was the original Script logic it replaced?
Map to current admin config: each Function is activated via Admin → Discounts (or Shipping / Payments). Note: which discount uses which Function, what the eligibility rules are, what the combinations setting is.
Document in a spreadsheet: Function name, type, source code location, business purpose, admin activation, last-known-good date.
Step 2
Admin → Apps → your Functions app → Logs. Look for execution errors, timeouts, and unusual patterns.
Apps → click your Functions app → Logs (or Function logs).
Filter to the last 30 days. Look at: total executions, error rate, average execution time, recent error messages.
Common error patterns: (1) timeout (execution > 5ms — usually means a large cart hit the limit), (2) input parse error (GraphQL schema changed, code didn't update), (3) output validation error (returned malformed result), (4) runtime exception (null reference, type mismatch).
Error rate over 1% = a real problem. Open recent error logs, find the input that caused the error, reproduce in sandbox.
If error rate is 0% but you still have bugs, the Function is silently 'not applying' for conditions you didn't anticipate. Move to step 3.
Step 3
Diagnostic gold: a reproducible test case. Re-create the exact cart/customer/conditions that triggers the bug.
Start with a customer complaint or revenue anomaly. Get the order details: cart contents, customer, time, discount expected, discount actually applied.
In sandbox, create a customer with the same characteristics (Company assignment if B2B, tags, country).
Build a cart with the same products and quantities.
Apply the same discount code (or trigger the automatic discount).
Walk through checkout. Note the discount amount, shipping rates, payment methods shown. Compare to expected.
If the bug doesn't reproduce: there's something different about the production order. Common: time-based (sale ended), customer-based (different tag), market-based (different country pricing).
If the bug reproduces: you have a fix target.
Step 4
Functions are code. Open the source (usually src/run.ts or src/lib.rs) and trace the logic against the reproducing test case.
Open the Function source. Find the main `run` (or `function_run`) entry point.
Trace the logic line by line against the test input. Use console.log() or println!() to print intermediate values.
Test locally: `shopify app function run` with the test case input. Verify what the Function actually returns vs what you expect.
Common bugs: (1) condition uses `===` for type-incompatible types, (2) variant ID mismatch (variant IDs differ in sandbox vs prod), (3) currency mismatch (Function assumes USD, multi-currency store sends GBP), (4) edge case not handled (empty cart, gift card only cart, B2B cart).
Once you find the bug, fix the source, redeploy via `shopify app deploy`, and re-test.
Step 5
Many "Function not applying" bugs are actually correct Function behavior + wrong admin settings. Verify combinations.
Admin → Discounts → click the discount linked to your Function → Combinations.
Combinations control: can this discount stack with other product discounts? Order discounts? Shipping discounts? Auto-discount + code discount?
Common bug: Function applies 10% off correctly, but admin combinations say 'don't combine with code discounts.' Customer also enters a free-shipping code → free shipping wins, 10% off doesn't apply. Customer thinks the discount is broken.
Fix: configure combinations to allow stacking where intended. Test with a cart that has multiple eligible discounts.
Also check: 'Customer eligibility' (all customers, specific segments, B2B Companies). A Function might be perfect but admin gating excludes the customer who's seeing the bug.
Step 6
Old Scripts often handled edge cases via side effects (modifying cart line attributes, calling other Scripts). Functions can't. Find the gap.
Common Script-vs-Function edge case gaps: (1) Scripts could modify line item properties, Functions can't (they only return discount/shipping/payment decisions), (2) Scripts could call APIs, Functions are pure logic, (3) Scripts could set order tags, only Flow can now.
Audit each Function's Script predecessor: did the Script do anything Functions can't? If yes, that work needs to move to a Flow workflow, a webhook, or a checkout UI extension.
Common issue: Script modified line item description ('add Gift Wrap'). Functions can't. Customer sees no gift wrap on receipt. Solution: move to a checkout UI extension that adds the property.
Common issue: Script called an external API for fraud check. Functions can't (no network access). Solution: move to a Flow webhook trigger that calls the API and tags the order.
Step 7
Once the Function is fixed, deploy to production, monitor logs for 48 hours, document the bug and fix for next time.
Deploy the fix: `shopify app deploy` (after testing in sandbox). Confirm deploy succeeded.
Monitor logs for the next 48 hours: error rate should drop or remain low. Execution time should be stable.
Audit a sample of recent orders to confirm the bug is fixed. Use Shopify Admin → Orders → filter by date → spot-check 10-20 orders.
Document the bug, root cause, and fix in your team wiki. Include: original Script intent, what broke in Functions, how you debugged, what the fix was.
Add a regression test: in your CI, run `shopify app function run` with the reproducing input and assert the output matches expectations. Prevents the bug from recurring.
Common mistakes
Trying to debug without the Function source code
What goes wrong: Original dev left, source code lives only on their laptop, no git repo. Now you can't read what the Function does. The only fix is rewriting from scratch — typically 1-2 weeks of work per Function.
How to avoid: Always keep Function source in your team git repo. If the source is lost, use `shopify app pull` (CLI) to fetch the deployed version. If that fails, rewrite is the only path.
Not testing in sandbox before deploying fixes
What goes wrong: Deploy a 'fix' that breaks something else (regression). Now customers experience two bugs instead of one. Revenue impact compounds.
How to avoid: Every fix gets tested in sandbox first with the reproducing test case AND a battery of other test cases. Only deploy to prod when sandbox passes.
Ignoring the 5ms execution-time limit
What goes wrong: Function works for 95% of carts and fails (silently) for the 5% of large carts that exceed 5ms execution. Discount doesn't apply on those carts. High-value B2B customers especially affected.
How to avoid: Profile Function execution time with worst-case inputs. If >5ms in JS, switch to Rust or optimize the GraphQL query to fetch less data.
Confusing 'Function deployed' with 'Discount active'
What goes wrong: Devs assume that running `shopify app deploy` makes the Function 'work.' It doesn't — it just makes the Function available. The discount must also be created in admin → Discounts → New Discount → Custom → select the Function. Without that, the Function does nothing.
How to avoid: After every deploy of a new Function, configure the corresponding discount/shipping/payment rule in admin. Document the activation step in your runbook.
Mixing old Scripts and new Functions concurrently
What goes wrong: Some discounts still go through old Scripts (because Scripts still run for now), others through Functions. Logic diverges. Same customer sees different behavior depending on which discount applies. Debugging is impossible.
How to avoid: Migrate ALL Scripts to Functions in one push. Don't leave half-migrated state for more than 1-2 weeks. Old Scripts are deprecated and will sunset — they're technical debt.
No version control or rollback plan
What goes wrong: Deploy a broken Function. No way to rollback. Live store has a broken discount for the time it takes to write + deploy + activate a fix. Typical impact: 2-12 hours of broken discount + revenue loss.
How to avoid: Use git. Every deploy is a commit. Rollback = revert the commit and redeploy the previous version. Test the rollback procedure once when nothing is broken so you know it works.
Recap
Done — what's next
How to set up Shopify Functions (the Scripts replacement)
Read the next tutorial
Hand it off
Functions debugging requires reading TypeScript or Rust and running a CLI. If you don't have a dev who's debugged 10+ Functions, this is the canonical hire-a-specialist task. A Shopify Plus dev specialist at $14-16/hr can audit and fix your Functions stack in 1-2 weeks — typically $1,200-2,400 total — and document the runbook so future bugs are 90 minutes, not 2 weeks.
See specialist rates
Yes, via git. Each deploy is a commit. To roll back: `git revert <bad-commit>`, push, and `shopify app deploy` deploys the previous code. If you don't have git, you can re-deploy from a previous version of the code — but only if you have it locally.
Shopify Admin → Apps → your Functions app → Logs (or Function logs). Shows every execution: input, output, errors, execution time. Filter by date and error status.
Common causes: (1) variant IDs differ between sandbox and prod (a hardcoded variant ID won't match), (2) customer segments differ (Function checks a tag that doesn't exist in prod), (3) discount activation/combinations differ in admin between sandbox and prod, (4) prod has higher cart volumes that exceed execution-time limits.
Yes, technically — but it's a recipe for bugs. Both might fire on the same cart, with unclear stacking. Don't do it. Migrate fully off Scripts.
Generally faster (Rust Functions especially). JavaScript Functions are comparable. The 5ms limit is strict but most well-written Functions execute in 1-2ms. If you're hitting the limit, you're probably fetching too much data in the GraphQL query.
Shopify Plus
Shopify Functions are the official Scripts replacement. They run server-side at checkout, written in JavaScript or Rust, deployed via CLI. Most Plus brands need 3-7 Functions to replicate their old Scripts. Here's how to build the first one.
Shopify Plus
Shopify→Plus is technically an in-place upgrade. Practically, it's a 30-day project once you factor in Scripts→Functions, B2B activation, and the apps that change pricing model on Plus. Here's the cutover plan.
Shopify Plus
On standard Shopify, checkout extensibility is mostly settings. On Plus, it's UI extensions, branding APIs, and Functions — code-deployed, version-controlled, infinitely flexible. The wrong setup is also infinitely expensive.
Shopify Plus
Shopify Flow is the free Plus-included automation tool. Most brands install it, build one workflow, then forget about it. The brands that get value out of Flow build 10-20 workflows that run silently in the background.
Shopify
Your Meta pixel was firing yesterday. Today, Events Manager shows zero purchases. Welcome to one of the most common Shopify-stack failures — and one of the most expensive if it goes unnoticed. Here's the diagnostic sequence.