惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
T
Tor Project blog
U
Unit 42
G
Google Developers Blog
T
The Blog of Author Tim Ferriss
Recorded Future
Recorded Future
B
Blog
I
InfoQ
H
Help Net Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
aimingoo的专栏
aimingoo的专栏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
小众软件
小众软件
Spread Privacy
Spread Privacy
T
Tenable Blog
C
Cybersecurity and Infrastructure Security Agency CISA
F
Fortinet All Blogs
Microsoft Security Blog
Microsoft Security Blog
I
Intezer
P
Proofpoint News Feed
A
About on SuperTechFans
S
Securelist
D
DataBreaches.Net
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
大猫的无限游戏
大猫的无限游戏
Cyberwarzone
Cyberwarzone
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
MyScale Blog
MyScale Blog
V
Visual Studio Blog
A
Arctic Wolf
Hugging Face - Blog
Hugging Face - Blog
Project Zero
Project Zero
博客园 - 司徒正美
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog RSS Feed
Vercel News
Vercel News
T
Threatpost
博客园 - Franky
有赞技术团队
有赞技术团队
爱范儿
爱范儿
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
L
LINUX DO - 热门话题

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Shopify Functions vs Shopify Scripts: A Migration Walkthrough
Alex Massaad · 2026-05-22 · via DEV Community

We covered the Scripts deprecation in an earlier post. The short version: Shopify Scripts stop running on June 30, 2026, and Shopify Functions are the replacement. As of April 15, 2026, you can no longer edit or publish new Scripts, which means Plus merchants who haven't migrated yet are now in the danger zone.

This post is the next layer down. It's the walkthrough. What the actual migration looks like in code, what breaks in translation, and the order we run the work in when a client hands us a Script Editor full of Ruby and asks us to make it Functions.

If you have a developer on your team, this gives them a sane starting point. If you don't, it gives you a clear picture of what you're hiring for.

The Mental Model Shift

Scripts and Functions solve the same problem in very different ways. The biggest mistake we see is people trying to port Scripts line-by-line. That doesn't work, because the underlying contract is different.

Scripts: Ruby code that runs inside Shopify's checkout, mutates a Cart object directly, and returns the mutated cart. You read properties, you write properties, you're done.

Functions: A WebAssembly module that receives a GraphQL input, returns a list of operations (FunctionRunResult), and lets Shopify apply those operations. You don't mutate state. You declare what should change.

If you internalize that one shift, the rest of the migration is mechanical.

The Migration Order We Run

We don't write a single line of Function code until steps 1 through 3 are done. Skipping ahead is how migrations slip three weeks past the deadline.

  1. Audit the Scripts. Read every active Script in Script Editor. Write down what each one does in plain English, including edge cases. Half the time, a Script does something the merchant forgot was even live.
  2. Map to native features. Shopify's native discount and checkout customization features have grown a lot since 2016. Several Scripts we audit each year don't need to become Functions. They can become native Automatic Discounts or Discount Combinations.
  3. Group what's left. The leftover Scripts get grouped by extension point. Discount logic goes to a Discount Function. Shipping logic goes to a Delivery Customization Function. Payment logic goes to a Payment Customization Function.
  4. Pick the toolchain. We build Functions on Gadget.dev because it cuts the boilerplate dramatically, but vanilla Shopify CLI plus a Rust or JS template works fine for a one-off.
  5. Translate, deploy, test in a development store, then promote. Never test Function changes against the live checkout. Use a dev store with the same product catalog shape.

A Real Translation: Tiered Discount

Here's the canonical "buy more, save more" Script that almost every Plus merchant has some version of.

Before (Ruby Script):

class TieredDiscount
  def run(cart)
    quantity = cart.line_items.reduce(0) { |sum, item| sum + item.quantity }

    discount_percent = case quantity
      when 0..2 then 0
      when 3..5 then 10
      when 6..9 then 15
      else 20
    end

    return if discount_percent == 0

    cart.line_items.each do |line_item|
      line_item.change_line_price(
        line_item.line_price * (Decimal.new(100 - discount_percent) / 100),
        message: "Tier discount (#{discount_percent}% off)"
      )
    end
  end
end

TieredDiscount.new.run(Input.cart)
Output.cart = Input.cart

Enter fullscreen mode Exit fullscreen mode

After (Shopify Function in JavaScript):

// src/run.js
export function run(input) {
  const totalQuantity = input.cart.lines.reduce(
    (sum, line) => sum + line.quantity,
    0
  );

  const discountPercent =
    totalQuantity >= 10 ? 20 :
    totalQuantity >= 6  ? 15 :
    totalQuantity >= 3  ? 10 : 0;

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

  return {
    discounts: [
      {
        message: `Tier discount (${discountPercent}% off)`,
        targets: input.cart.lines.map((line) => ({
          productVariant: { id: line.merchandise.id, quantity: line.quantity }
        })),
        value: { percentage: { value: discountPercent.toString() } }
      }
    ],
    discountApplicationStrategy: "FIRST"
  };
}

Enter fullscreen mode Exit fullscreen mode

A few things to notice in the diff:

  • No mutation. We return a discounts array, we don't reach into the cart and rewrite line prices.
  • Targets are explicit. Scripts let you call change_line_price on each line. Functions ask you to declare which variants the discount applies to and how it stacks via discountApplicationStrategy.
  • The data shape is GraphQL. cart.line_items is now cart.lines, line_item.quantity is now line.quantity, and you'll spend the first hour of every migration relearning these names.

The GraphQL Input File Is Where People Get Stuck

Functions don't receive the entire cart. They receive whatever you ask for in an input.graphql query. This is the file that surprises every developer the first time.

# src/input.graphql
query Input {
  cart {
    lines {
      quantity
      merchandise {
        ... on ProductVariant {
          id
          product {
            id
            tags
          }
        }
      }
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

If you forget to query tags here, you cannot read tags inside run.js, no matter how many console.log calls you add. The first hour of debugging a misbehaving Function is almost always "the input query is missing a field."

Shipping and Payment Customization

Scripts had a single execution point: checkout. Functions split that into separate APIs:

  • Delivery Customization Function for shipping. Hide options, rename them, reorder them.
  • Payment Customization Function for payment methods. Same operations.
  • Cart Transform Function if you need to expand a single line into multiple lines (bundles, components).

A Script that hid Express Shipping for heavy carts becomes a Delivery Customization Function that returns a hide operation:

export function run(input) {
  const totalGrams = input.cart.lines.reduce(
    (sum, line) => sum + (line.merchandise.weight ?? 0) * line.quantity,
    0
  );

  if (totalGrams < 20000) {
    return { operations: [] };
  }

  const expressOption = input.cart.deliveryGroups
    .flatMap((group) => group.deliveryOptions)
    .find((option) => option.title === "Express");

  if (!expressOption) {
    return { operations: [] };
  }

  return {
    operations: [
      { hide: { deliveryOptionHandle: expressOption.handle } }
    ]
  };
}

Enter fullscreen mode Exit fullscreen mode

The pattern is consistent across all three customization APIs: query what you need, decide what should change, return operations.

Gotchas We Hit Often

These are the ones that have actually cost us hours, not the ones we read about.

The instruction-count limit is real. Functions enforce a strict execution budget measured in instructions (around 11 million), not wall-clock time, along with a 125KB input size cap. Loops over the entire catalog, regex on every line item description, and deeply nested .find() chains will blow past it on a busy cart. Profile early.

undefined vs missing fields. GraphQL only returns what you queried. If a field isn't in input.graphql, it's not null in your input object, it's not present at all. Defensive code matters.

No external HTTP calls. Scripts didn't allow them either, but people sometimes assume Functions do because Functions are deployed as part of an app. They don't. If you need data from outside Shopify, fetch it ahead of time and pass it through metafields.

Discount stacking. Scripts let you stack discounts implicitly. Functions force you to declare a discountApplicationStrategy of FIRST or MAXIMUM. Pick the wrong one and your customers see different totals than they did under Scripts.

Localization and currency. Scripts gave you the cart's currency on the cart object. In Functions, you query it via cart.cost.totalAmount.currencyCode (or similar paths depending on the API). Hardcoding CAD because the dev store is in CAD is the kind of bug that ships to a US store and breaks Black Friday.

Testing tools are different. Scripts had a console in the admin. Functions are tested with shopify app function run against fixture inputs. Build out a small set of fixture carts that represent your real edge cases, and run them on every change.

How Long Does a Migration Take?

For a single straightforward Script (one rule, one extension point), expect a day of work end to end. Audit, translate, test, deploy.

For a Plus merchant with eight to twelve active Scripts spread across discounts, shipping, and payment, expect two to three weeks. Most of that time is in steps 1, 2, and 5. The actual coding is the smallest part.

If your store has Scripts you've forgotten about, has Scripts written by someone who left the company, or has Scripts that interact with each other in ways nobody documented, double the estimate. We've seen migrations that took six weeks because the audit kept turning up new edge cases.

How We Run Scripts to Functions Migrations

When clients bring us this work, our process is:

  1. Read-only audit week. We get Script Editor access, document everything, and produce a migration plan with native-feature swaps called out.
  2. Build week(s). Functions written, deployed to a dev store, tested against fixture carts that match the merchant's real traffic.
  3. Cutover. Functions enabled in production, Scripts disabled the same day. We watch checkout closely for 48 hours.
  4. Post-cutover review. We document what changed and hand the codebase off, since Functions live in a real Git repo, not in an admin panel.

If you're sitting on Scripts and the June 30 deadline is starting to feel close, get in touch. We can run the audit week and tell you exactly how big the project is before you commit to a build. For more on how we build Functions and apps quickly, see why we build Shopify apps on Gadget.dev and our Shopify app development service.

The Bottom Line

The migration isn't conceptually hard. It's a translation job between two systems that solve the same problem. The discipline is in the audit and the testing, not the coding. Start with what you have, map what's native, and write Functions only for what's actually left.

The merchants who started this work in 2025 are done. The ones who started in early 2026 are mid-project. The ones who haven't started yet still have time, but the runway is roughly eight weeks and shrinking.