이 글의 목차
오늘은 2026년 4월 16일입니다. 어제인 4월 15일, Shopify는 Script Editor를 완전히 잠갔습니다. 이제 새 Script를 만들거나 게시할 수 없습니다. 이 기한은 구매 후 처리 로직에 특히 큰 영향을 줍니다. 배송 주소 변경은 구매 후 주문 수정 중 가장 많으며, 수정된 주문의 30.2%를 차지합니다(Revize, 2026). 이 작업을 처리하는 Script가 있다면 이제 수정할 수 없습니다. 실행은 75일 뒤인 2026년 6월 30일 중단됩니다.
Shopify Plus 개발자이거나 Plus 스토어를 운영하는 에이전시로서 지난 12개월 동안 이 이전 작업을 ‘다음 스프린트’로 미뤘다면, 이제 문제가 생겼습니다. 나중에 고쳐도 되는 문제가 아닙니다. 7월 1일 자정에 결제(체크아웃)가 제대로 작동하지 않을 수 있는 문제입니다. 대부분의 Plus 스토어에는 수년간 쌓인 Script가 5~20개 있습니다. 누가 작성했는지 기억하지 못하는 할인 규칙, 배송 옵션 숨김, 결제 수단 제한이 각각의 Script에서 조용히 작동하고 있습니다.
이 가이드는 1월에 있었으면 좋았을 기술 이전 설명서입니다. 전략에 그치지 않고 실제 코드를 다룹니다. 끝까지 읽으면 Shopify CLI로 Function을 생성하고, Rust 또는 JavaScript로 할인·배송 맞춤 설정·결제 맞춤 설정 로직을 작성하고, 태그를 지정한 일부 고객을 대상으로 안전하게 테스트한 뒤, 기존 결제(체크아웃)에 문제를 일으키지 않고 프로덕션에 배포하는 방법을 알 수 있습니다.
스토어의 Scripts를 Functions로 옮겨 보겠습니다.

빠른 답변: 60초 만에 이해하는 Scripts → Functions
한 문단으로 보는 이전 작업: Shopify Scripts는 Script Editor에서 작성하는 Ruby 코드로, Plus에서만 사용할 수 있습니다. 이를 Shopify Functions가 대체합니다. Functions는 Rust 또는 JavaScript로 작성하는 WebAssembly 모듈이며 모든 요금제에서 사용할 수 있습니다.
shopify app generate extension으로 Function을 생성하고, 필요한 장바구니 데이터를 가져오는run.graphql쿼리를 작성합니다. 그런 다음 할인이나 배송 옵션 숨김 같은 작업을 반환하는run.rs또는run.js파일을 작성합니다. 마지막으로shopify app deploy로 배포하고 Shopify Admin 또는 GraphQL 뮤테이션으로 활성화합니다. Functions는 컴파일된 WASM으로 실행되며 지연 시간은 5ms 미만입니다. 모든 요금제에서 실행되고, 앞으로 Shopify가 지원하는 유일한 맞춤 설정 경로입니다.
6월 30일에 실제로 달라지는 점
코드를 살펴보기 전에 날짜부터 확인하겠습니다. 중요한 날짜는 두 개입니다.
| 날짜 | 변경 사항 | 해야 할 일 |
|---|---|---|
| 2026년 4월 15일 (지남) | Script Editor가 읽기 전용으로 전환됩니다. 새 Script를 만들거나 기존 Script를 수정할 수 없습니다. | 기존 Scripts는 계속 실행됩니다. 지금 이전하지 않으면 로직을 수정할 수 없는 상태로 두게 됩니다. |
| 2026년 6월 30일 | 모든 Shopify Scripts의 실행이 중단됩니다. | 이 날짜 전에 대체 Function을 운영 환경에 적용해야 합니다. |
이전 결과는 둘 중 하나입니다. 6월 30일까지 Function을 배포해 결제(체크아웃)가 계속 작동하거나, 배포하지 못해 영향받는 모든 장바구니에 기본 가격, 기본 배송비, 활성화된 모든 결제 수단이 그대로 적용됩니다. 일부만 이전한 것으로는 해결되지 않습니다. Script는 실행되거나 실행되지 않으며, 6월 30일 이후에는 실행되지 않습니다.
팁: Shopify Admin에서
Settings → Checkout → Customizations Report를 여세요. 스토어에서 활성화된 모든 Script, 각 Script의 기능, 권장되는 대체 Function 유형을 확인할 수 있습니다. 여기서 시작하세요.
Functions와 Scripts: 실제로 바뀐 점
| 항목 | Shopify Scripts (지원 중단) | Shopify Functions (대체 수단) |
|---|---|---|
| 언어 | Ruby DSL(Shopify 전용) | Rust, JavaScript, TypeScript |
| 실행 환경 | Shopify 인프라의 샌드박스형 Ruby | WebAssembly(WASM) — 실행 시간 5ms 미만 |
| 이용 가능 요금제 | Plus 전용 | 모든 요금제(사용자 지정 앱에는 Plus가 필요하며 공개 앱은 모든 요금제에서 사용 가능) |
| 편집 도구 | Shopify Admin의 Script Editor | 로컬 IDE + Shopify CLI |
| 버전 관리 | 없음 — 즉시 반영되는 수정 | Git으로 전체 버전 관리 가능 |
| 테스트 | 결제(체크아웃)에서 수동 테스트 | shopify app dev를 이용한 로컬 개발, 미리보기 링크 |
| 배포 | Shopify Admin에서 ‘저장’ 클릭 | 터미널에서 shopify app deploy 실행 |
| 적용 대상 | 품목, 배송, 결제 | 할인, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints 등 |
구조 자체가 바뀝니다. Scripts에서는 텍스트 상자에서 Ruby를 수정했습니다. Functions에서는 실제 앱을 작성하고, 버전을 관리하고, 로컬에서 테스트한 뒤 CI 파이프라인으로 배포합니다. 시작할 때 익혀야 할 것은 더 많습니다. 하지만 Functions는 Shopify가 장기적으로 지원하기로 한 방식입니다. Scripts처럼 임시로 쓰다가 교체하는 수단이 아니므로, 당분간 결제(체크아웃) 로직을 다시 이전할 일은 없을 것입니다.
각 Script에 맞는 Function 유형 찾기
현재 사용하는 각 Script는 하나의 Function API에 대응합니다. 아래 표를 참고하세요.
| 기존 Script 유형 | 하던 일 | 새 Function API | Function 대상 |
|---|---|---|---|
| Line Item Script | 특정 상품, 고객 또는 장바구니 조건에 할인 적용 | Cart & Checkout Discounts API | cart.lines.discounts.generate.run |
| Shipping Script (할인) | 장바구니 규칙에 따라 무료 또는 할인 배송 제공 | Cart & Checkout Discounts API | cart.delivery-options.discounts.generate.run |
| Shipping Script (숨김 / 이름 변경 / 순서 변경) | $X를 초과하면 배송 요금을 숨기거나, “Standard”를 “Free over $50”으로 변경 | Delivery Customization API | cart.delivery-options.transform.run |
| Payment Script | B2B 고객에게 PayPal을 숨기거나, $500를 초과하면 COD를 숨기거나, 결제 수단 순서를 변경 | Payment Customization API | cart.payment-methods.transform.run |
| 장바구니를 수정하는 Script(드묾) | 상품을 묶거나 품목을 교체 | Cart Transform API | cart.transform.run |
| 결제(체크아웃)를 차단하는 Script | SKU 조합이 유효하지 않으면 장바구니 거부 | Cart & Checkout Validation API | cart.validations.generate.run |
Script가 열 개라도 Function은 세 개에서 다섯 개 정도만 만들 수 있습니다. 여러 Script를 분기 로직이 더 명확한 하나의 Function으로 합칠 수 있기 때문입니다.

사전 준비: 로컬 개발 환경 설정
Function을 생성하기 전에 로컬에 세 가지를 설치해야 합니다. 터미널에서 다음 항목을 확인하세요.
1. Node.js 18 이상
node --version
# Must be >= 18.0.0버전이 낮다면 nvm으로 설치하거나 nodejs.org에서 다운로드하세요.
2. Shopify CLI 3 이상
npm install -g @shopify/cli@latest
shopify version
# Should output 3.x or higher3. Rust 도구 체인(Rust로 Functions를 작성할 때만 필요)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --versionJavaScript Functions에는 Rust가 필요하지 않습니다. 팀에서 사용할 언어 하나를 정해 일관되게 사용하세요. 두 언어를 섞으면 유지 관리 부담이 늘어납니다.
4. 개발 스토어
Partner 대시보드에 로그인해 새 개발 스토어를 만들거나 기존 개발 스토어를 사용하세요. 프로덕션에 적용하기 전에 이 스토어에 Functions를 배포합니다.
첫 Function 생성하기
CLI가 기본 파일을 대부분 만들어 줍니다. 아무 디렉터리에서나 다음 명령을 실행하세요.
# Create a new Shopify app (skip if you already have one)
shopify app init my-checkout-functions
cd my-checkout-functions
# Generate a Function extension
shopify app generate extensionCLI가 선택 항목을 차례로 안내합니다. 할인 Function이라면 다음과 같이 선택합니다.
- 유형: Function
- 템플릿:
discount(또는cart_checkout_validation,delivery_customization,payment_customization등) - 언어: Rust 또는 JavaScript
- 이름:
volume-discount-fn같은 이름
그러면 다음 파일이 포함된 extensions/volume-discount-fn/ 디렉터리가 만들어집니다.
extensions/volume-discount-fn/
├── shopify.extension.toml # Function config — targets, build, version
├── src/
│ ├── cart_lines_discounts_generate_run.graphql # Input query
│ └── cart_lines_discounts_generate_run.rs # Function logic
├── Cargo.toml # Rust dependencies (Rust only)
└── README.md주로 수정할 파일은 설정을 담은 .toml, 입력 데이터를 정하는 .graphql, 로직을 담은 .rs / .js 세 가지입니다.
튜토리얼 1: Line Item Script 대체하기(수량 할인)
기존 Script가 특정 컬렉션의 상품을 장바구니에 5개 이상 담으면 주문 소계에서 10%를 할인했다고 가정해 보겠습니다. 이에 해당하는 Function은 다음과 같습니다.
1.1단계: 설정(shopify.extension.toml)
api_version = "2026-01"
[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"
[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"
[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]1.2단계: 입력 쿼리(src/cart_lines_discounts_generate_run.graphql)
query Input {
cart {
lines {
id
quantity
cost {
subtotalAmount {
amount
}
}
merchandise {
... on ProductVariant {
product {
inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
}
}
}
}
}
discount {
discountClasses
}
}팁: Functions는 쿼리로 요청한 데이터만 볼 수 있습니다. GraphQL 쿼리는 필요한 필드만 포함하세요. 불필요한 필드를 줄일수록 더 빠르고 적은 비용으로 실행할 수 있습니다.
1.3단계: 로직(src/cart_lines_discounts_generate_run.rs)
use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;
#[shopify_function]
fn cart_lines_discounts_generate_run(
input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
// Bail if discount class doesn't match
let has_order_discount = input
.discount()
.discount_classes()
.contains(&schema::DiscountClass::Order);
if !has_order_discount {
return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
}
// Sum quantities of items in the target collection
let qualifying_qty: i64 = input
.cart()
.lines()
.iter()
.filter(|line| {
if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
*v.product().in_any_collection()
} else {
false
}
})
.map(|line| *line.quantity())
.sum();
if qualifying_qty < 5 {
return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
}
// Apply 10% off the order subtotal
Ok(schema::CartLinesDiscountsGenerateRunResult {
operations: vec![schema::CartOperation::OrderDiscountsAdd(
schema::OrderDiscountsAddOperation {
selection_strategy: schema::OrderDiscountSelectionStrategy::First,
candidates: vec![schema::OrderDiscountCandidate {
targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
schema::OrderSubtotalTarget {
excluded_cart_line_ids: vec![],
},
)],
message: Some("Volume discount: 10% off".to_string()),
value: schema::OrderDiscountCandidateValue::Percentage(
schema::Percentage { value: Decimal(10.0) }
),
conditions: None,
associated_discount_code: None,
}],
},
)],
})
}1.4단계: 테스트, 배포, 활성화
# Local development with hot reload
shopify app dev
# When ready, deploy
shopify app deploy
# In the GraphiQL panel that opens (press `g` in the dev terminal),
# create the automatic discount that uses your Function:mutation {
discountAutomaticAppCreate(
automaticAppDiscount: {
title: "Volume Discount (5+ collection items)"
functionHandle: "volume-discount-fn"
discountClasses: [ORDER]
startsAt: "2026-04-16T00:00:00Z"
}
) {
automaticAppDiscount { discountId }
userErrors { field message }
}
}이제 Function이 운영 환경에서 작동합니다. 버전 관리도 가능하며 기존 Script를 완전히 대체합니다.
튜토리얼 2: Shipping Script 대체하기(장바구니 금액에 따라 배송 옵션 숨기기)
흔한 Script 중 하나는 ‘큰 주문에 비싼 익일 배송비가 적용되지 않도록 장바구니 소계가 $500를 넘으면 Express Shipping을 숨긴다’는 규칙입니다. Delivery Customization Function으로 구현하면 다음과 같습니다.
2.1단계: 생성
shopify app generate extension --template delivery_customization --name hide-express-fn2.2단계: 입력 쿼리(src/run.graphql)
query Input {
cart {
cost {
subtotalAmount {
amount
}
}
deliveryGroups {
deliveryOptions {
handle
title
}
}
}
}2.3단계: 로직(src/run.js — JavaScript 버전)
// @ts-check
/**
* @typedef {import("../generated/api").RunInput} RunInput
* @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
*/
const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];
/**
* @param {RunInput} input
* @returns {FunctionRunResult}
*/
export function run(input) {
const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
if (subtotal < THRESHOLD) return NO_CHANGES;
const operations = input.cart.deliveryGroups.flatMap((group) =>
group.deliveryOptions
.filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
.map((opt) => ({
hide: { deliveryOptionHandle: opt.handle },
}))
);
return { operations };
}2.4단계: Shopify Admin에서 활성화(GraphQL 불필요)
Delivery Customizations에는 Shopify Admin UI가 기본 제공됩니다. shopify app deploy를 실행한 뒤 다음 단계를 따르세요.
- Settings → Shipping and delivery로 이동합니다.
- 화면 아래쪽의 Customizations 섹션으로 스크롤합니다.
- Add customization을 클릭하고 Function을 선택합니다.
- 저장합니다.
이제 배송 옵션 숨김 규칙이 프로덕션에서 작동합니다. 뮤테이션은 필요하지 않습니다.

튜토리얼 3: Payment Script 대체하기(B2B 고객에게 COD 숨기기)
기존 Script가 ‘B2B’ 태그가 있는 고객에게 착불 결제를 숨겼다고 가정해 보겠습니다. Payment Customization으로 구현하는 방법은 다음과 같습니다.
3.1단계: 생성
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn3.2단계: 입력 쿼리
query Input {
cart {
buyerIdentity {
customer {
hasTags(tags: [{ tag: "B2B" }]) {
tag
hasTag
}
}
}
}
paymentMethods {
id
name
}
}3.3단계: 로직(src/run.js)
const NO_CHANGES = { operations: [] };
export function run(input) {
const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
const isB2B = tagCheck?.hasTag === true;
if (!isB2B) return NO_CHANGES;
const codMethod = input.paymentMethods.find((pm) =>
pm.name.toLowerCase().includes("cash on delivery")
);
if (!codMethod) return NO_CHANGES;
return {
operations: [{ hide: { paymentMethodId: codMethod.id } }],
};
}3.4단계: 활성화
Payment Customizations에도 Settings → Payments → Customizations에 Shopify Admin UI가 있습니다. 배송 맞춤 설정과 같은 방식으로 Function을 선택하고 저장하면 됩니다.
이 글을 읽고 계시다면: 구매 후 주문 수정에 관해
이곳이 Revize 블로그인 만큼 짧게 설명드리겠습니다. Revize는 Functions가 처리할 수 없는 구매 후 작업을 맡습니다. 주문을 완료한 고객은 상품을 추가하거나, 사이즈를 바꾸거나, 배송 주소를 수정하거나, 빠뜨린 할인을 적용하고 싶어 합니다. Functions는 결제(체크아웃) 단계에서 작동하고, Revize는 결제 후에 작동합니다. Functions는 장바구니에서 허용할 작업을 결정합니다. Revize는 고객과 지원팀이 환불 후 주문을 다시 만드는 절차 없이 기존 주문을 수정할 수 있게 합니다. 이는 두 유형의 스토어에 중요합니다. 주문량이 많아 수동 수정으로 감당하기 어려운 스토어(Plus 운영 스토어는 물론 주문 처리량이 많은 Advanced 스토어 포함)와 고객 경험을 브랜드의 핵심으로 삼는 스토어입니다. 후자의 경우 ‘죄송하지만 변경할 수 없습니다’라는 이메일 한 통이 재구매를 막을 수 있습니다.
Scripts → Functions 이전 계획은 세웠지만 구매 후 주문 수정은 아직 정리하지 않았다면, 약 3주 뒤 또다시 ‘왜 이렇게 어렵지?’라는 문제를 만나게 될 수 있습니다. 최근 게시한 주문 관리 가이드에서 결제 후 처리 방법을 자세히 설명합니다.
이제 이전 작업으로 돌아가겠습니다.
테스트 전략: 고객 태그 활용하기
Functions에는 Shopify Admin에서 켜고 끌 수 있는 ‘초안 모드’가 없습니다. 실무에서는 고객 태그를 조건으로 새 Function의 실행을 제한합니다. 기존 Script와 새 Function을 병렬로 실행하면서 태그가 있는 사용자에게 같은 결과가 나오는지 확인한 뒤, 전체 고객에게 적용합니다.
1단계: 테스트 사용자에게 태그 지정
Customers에서 내부 계정 두세 개에 FN-TESTER 태그를 추가합니다.
2단계: 태그 유무에 따라 Function 분기
// At the top of your run function
let is_tester = input
.cart()
.buyer_identity()
.and_then(|bi| bi.customer())
.map(|c| c.has_any_tag())
.unwrap_or(&false);
if !*is_tester {
return Ok(default_result); // Fall through to existing Script
}
// New Function logic only runs for tagged users3단계: 입력 쿼리에 hasAnyTag 추가
cart {
buyerIdentity {
customer {
hasAnyTag(tags: ["FN-TESTER"])
}
}
}4단계: 결제(체크아웃)에서 확인
태그가 있는 사용자로 로그인해 결제(체크아웃)를 진행하고 Function이 실행되는지 확인합니다. 태그가 없는 사용자로도 로그인해 기존 Script가 계속 실행되는지 확인합니다. 며칠 동안 결과가 일치하면 태그 확인 로직을 제거하고 모든 고객에게 Function을 실행합니다.
5단계: 기존 Script 게시 취소
Apps → Script Editor → [Your Script] → Unpublish로 이동합니다. 게시를 취소하면 Function만 해당 로직을 담당합니다.
규모가 커져도 유지할 수 있는 배포 절차
계속 개발자의 노트북에서 배포하지는 마세요. Script 한두 개를 이전했다면 CI 파이프라인을 설정할 때입니다.
최소한의 배포 절차
# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- uses: dtolnay/rust-toolchain@stable
with: { targets: wasm32-wasip1 }
- run: npm install -g @shopify/cli@latest
- run: shopify app deploy --force
env:
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}Partner 대시보드의 Settings → Tokens에서 파트너 토큰을 생성합니다. 이제 main에 병합할 때마다 Functions가 배포됩니다. ‘Mike가 그거 배포했나?’라고 Slack에서 확인할 필요가 없습니다.
버전 관리와 롤백
shopify app deploy는 버전이 지정된 스냅샷을 만듭니다. 이전 버전으로 되돌리려면 다음을 실행하세요.
shopify app versions list
shopify app release --version <previous-version-id>롤백하려면 예전 코드를 기억해 다시 붙여 넣어야 했던 Scripts와는 큰 차이가 있습니다.

많은 팀이 놓치는 점
지난 1년간 Plus 판매자의 이전 작업을 도우면서 같은 실수 다섯 가지를 반복해서 봤습니다.
1. Functions를 Scripts의 1:1 복사본으로 취급합니다. 둘은 다릅니다. 분기 로직을 정리하면 Function 하나로 Scripts 세 개를 대체할 수도 있습니다. 다시 작성하기 전에 Scripts 전체를 함께 검토하세요.
2. 읽기 권한 범위를 잊습니다. 많은 Functions에 read_customers, read_orders 또는 write_discounts가 필요합니다. shopify.app.toml의 scopes에 추가하고 앱을 다시 승인하세요. 그렇지 않으면 입력 쿼리가 null을 반환합니다.
3. 결과 비교 없이 태그가 없는 고객에게 Functions를 실행합니다. 코드가 올바르게 보여도 빈 장바구니, 기프트 카드, 스토어 크레딧, B2B 주문 초안 같은 예외 상황에서 문제가 드러날 수 있습니다. 태그로 실행 대상을 제한해 출시하는 데 이틀이 더 걸리지만, 심각도 P1의 서비스 장애를 막을 수 있습니다.
4. Customizations Report를 건너뜁니다. 현재 실제로 실행 중인 항목을 확인하는 데 가장 좋은 자료입니다. 기억에 의존하지 말고 보고서를 기준으로 이전하세요.
5. 컬렉션 ID와 고객 태그를 코드에 고정합니다. 판매자가 값을 조정해야 한다면 메타필드를 통한 Function 설정을 사용하세요. CLI로 메타필드 기반 설정의 기본 파일을 생성할 수 있습니다. 자세한 내용은 Shopify의 Function 설정 문서를 참고하세요.
앞으로 75일간의 이전 체크리스트
6월 30일까지 무리 없이 마치기 위한 현실적인 주별 계획입니다.
| 기간 | 할 일 |
|---|---|
| 1주 차(이번 주) | Customizations Report를 가져옵니다. 모든 Script의 목록을 만듭니다. Function으로 이전할지, 공개 앱을 사용할지, 삭제할지 결정합니다. |
| 2~3주 차 | 로컬 개발 환경을 설정합니다. 첫 Function을 생성합니다. 가장 단순한 Script를 이전합니다. 보통 결제 수단을 숨기는 규칙이 여기에 해당합니다. |
| 4~6주 차 | 할인 Scripts를 이전합니다. Discounts API의 기능이 가장 많아 시간이 가장 오래 걸립니다. 태그를 이용해 충분히 테스트합니다. |
| 7~8주 차 | 배송 관련 Scripts를 이전합니다. Shopify Admin에서 Delivery Customizations를 활성화합니다. |
| 9~10주 차 | CI 파이프라인을 설정합니다. 개발자 노트북에서 직접 배포하는 방식을 모두 중단합니다. |
| 11주 차 (6월 중순) | 최종 결과 비교를 마칩니다. 모든 Scripts의 게시를 취소합니다. 2주 동안 Functions만으로 스토어를 운영합니다. |
| 6월 30일 | Scripts 종료일입니다. 작업을 미리 마쳤으므로 아무 문제도 발생하지 않습니다. |
이번 주에 시작하면 여유가 있습니다. 6월에 시작하면 여유가 없습니다.

자주 묻는 질문
Functions를 사용하려면 Shopify Plus가 필요한가요?
사용자 지정 Functions에는 Shopify Plus가 필요하지만, 공개 앱의 Functions는 모든 요금제에서 작동합니다. Plus를 사용하지 않는다면 두 가지 방법이 있습니다. 필요한 Function이 포함된 공개 앱을 Shopify App Store에서 설치하거나, 직접 사용자 지정 Functions를 작성하기 위해 Plus로 업그레이드할 수 있습니다. 기존에 Scripts를 사용하던 대형 판매자는 대부분 Plus를 사용하고 있었으므로, 실제로는 달라지는 점이 거의 없습니다.
TypeScript로 Functions를 작성할 수 있나요?
예. TypeScript를 완전히 지원하며 CLI가 필요한 기본 파일을 생성합니다. shopify app generate extension을 실행하고 ‘JavaScript’를 선택하면 생성된 프로젝트에 import("../generated/api")의 타입 선언이 포함됩니다. 원한다면 파일을 .ts로 바꾸고 tsconfig.json을 추가할 수 있습니다. 원본 언어와 관계없이 컴파일된 출력물(WASM)은 동일합니다.
Functions는 Scripts보다 얼마나 빠른가요?
Functions는 보통 5ms 미만에 실행되며 Ruby Scripts보다 훨씬 빠릅니다. WebAssembly로 컴파일되어 간결한 실행 환경에서 작동하므로 Shopify는 실행 시간을 5ms로 제한합니다. Function이 이를 초과하면 해당 작업이 폐기되고 Function은 아무 작업도 반환하지 않습니다. 실제로 잘 작성된 Function은 1~2ms가 걸립니다. 성능 면에서 Scripts보다 훨씬 높은 한계에 도달할 수 있습니다.
Function에서 외부 API를 호출할 수 있나요?
아니요. Functions는 네트워크 요청을 보낼 수 없습니다. 입력된 장바구니 데이터를 계산해 작업을 출력할 뿐입니다. CRM 조회나 실시간 재고 확인처럼 외부 데이터가 필요하다면 데이터를 미리 메타필드에 저장하거나, 다른 방식(App Proxy, 웹훅, 백엔드 조회를 사용하는 Cart Transform)을 사용해야 합니다. 팀이 단순 이전 대신 설계를 바꿔야 하는 가장 흔한 이유입니다.
Cart Transform과 Discounts는 어떻게 다른가요?
Discounts는 가격을 바꾸고, Cart Transform은 장바구니의 내용을 바꿉니다. 10% 할인, 무료 배송, 하나를 사면 하나를 더 주는 프로모션에는 Discounts API를 사용하세요. 두 상품을 하나의 품목으로 묶거나 한 옵션을 여러 품목으로 나누려면 Cart Transform을 사용하세요. 기존 Scripts에는 이 두 기능이 섞여 있는 경우가 많습니다. 이전할 때는 두 Function으로 분리하세요.
개발 스토어 없이 Function을 로컬에서 테스트할 수 있나요?
cargo test(Rust) 또는 npm test(JS)로 단위 테스트를 실행할 수 있지만, 전체 통합 테스트에는 개발 스토어가 필요합니다. CLI의 shopify app function run은 샘플 입력 파일을 사용해 Function을 실행하므로 빠르게 수정하며 테스트할 때 유용합니다. 하지만 결제(체크아웃)가 처음부터 끝까지 올바르게 작동하는지 확인하려면 실제 장바구니가 있는 스토어가 필요합니다.
같은 유형의 Function을 여러 개 사용할 수 있나요?
예. Shopify는 대상 하나에 여러 Functions를 지원하며, 이들은 정해진 순서로 실행됩니다. 할인의 실행 순서는 Shopify의 할인 중복 적용 규칙을 따릅니다. Delivery Customizations와 Payment Customizations에서는 Functions를 연달아 실행할 수 있으며, 앞선 출력이 다음 Function에 전달됩니다. 대부분의 팀은 단순하게 관리하기 위해 유형별로 Function 하나를 사용합니다.
Function을 배포하면 기존 Script는 어떻게 되나요?
Apps → Script Editor에서 Script의 게시를 취소하기 전까지 둘 다 병렬로 실행됩니다. 두 로직을 함께 테스트할 시간을 주기 위한 동작입니다. Function이 작동하는지 확인한 뒤 Script의 게시를 수동으로 취소하세요. 게시 취소 여부와 관계없이 모든 Scripts는 2026년 6월 30일 이후 실행되지 않습니다.
이전 작업이 SEO나 테마에 영향을 주나요?
아니요. Functions는 결제(체크아웃) 단계의 서버에서 실행되며 테마나 상품 페이지를 수정하지 않습니다. 결제(체크아웃)의 할인, 배송 옵션, 결제 수단만 변경합니다. 스토어프런트, 상품 템플릿, SEO에는 영향이 없습니다.
사용자 지정 속성과 함께 Input.line_items를 사용하는 Script는 어떻게 이전하나요?
사용자 지정 속성은 GraphQL 입력에서 장바구니 품목의 attribute 필드로 읽을 수 있습니다. lines 선택 항목 안에 attribute(key: "your-key") { value }를 추가하세요. Script가 Ruby 메서드 호출로 품목 속성을 읽던 것과 같은 값을 Function에서는 GraphQL로 읽습니다.
분석과 주문 태그는 어떻게 하나요? Functions가 데이터를 쓸 수 있나요?
Functions는 직접 주문 태그를 쓰거나 웹훅을 실행할 수 없습니다. 현재 장바구니에 적용할 작업만 반환합니다. 태그 지정이나 후속 작업에는 주문 생성 이벤트로 실행되는 Shopify Flow를 사용하세요. 많은 판매자가 할인에는 Function을, 주문에 “VOLUME-DISCOUNT-APPLIED” 태그를 지정하는 데는 Flow를 함께 사용합니다.
사용자 지정 Function을 만들지 않고 설치할 수 있는 공개 앱이 있나요?
예. Shopify App Store에는 흔한 용도의 Functions를 제공하는 앱이 수십 개 있습니다. ‘discount function’, ‘delivery customization’, ‘payment customization’으로 검색해 보세요. 수량 할인, 태그에 따른 결제 수단 숨김, X를 초과하는 주문의 무료 배송처럼 단순한 경우에는 기존 앱을 사용해 개발 시간을 며칠 줄일 수 있습니다. 비즈니스에 고유한 로직에만 사용자 지정 Functions를 사용하세요.
6월 30일 기한을 놓치면 어떻게 되나요?
Script 실행이 중단됩니다. 대체 동작도, 유예 기간도, 기한 연장도 없습니다. Script가 처리하던 할인, 숨겨진 배송 요금, 차단된 결제 수단은 7월 1일 UTC 자정에 기본 동작으로 돌아갑니다. 비즈니스가 그 로직에 의존한다면 그 날짜보다 훨씬 전에 Function을 운영 환경에 적용하세요. 특히 결과 비교 테스트까지 포함하면 이전 작업은 대부분의 팀이 예상하는 것보다 오래 걸립니다.
Script Editor 앱을 완전히 삭제해도 되나요?
2026년 6월 30일 이후 제거할 수 있으며, Shopify가 자동으로 제거할 가능성도 있습니다. Scripts가 더 이상 실행되지 않으면 편집기도 쓸모가 없습니다. 이전을 완료했다면 지금 모든 Scripts의 게시를 취소하고 앱을 바로 제거해도 됩니다. Functions는 별도로 작동합니다.
이번 주에 할 일
이 글을 읽고 탭만 닫지 마세요. 앞으로 7일 안에 다음 네 가지를 진행하세요.
1. Customizations Report를 가져오세요. Settings → Checkout → Customizations Report로 이동해 내보냅니다. 이 보고서가 이전 작업 목록입니다.
2. 개발 환경을 설정하세요. Node 18+, Shopify CLI, 필요하다면 Rust를 설치합니다. shopify version이 작동하는지 확인하세요. 예상 소요 시간은 30분입니다.
3. 작은 Function 하나를 생성해 개발 스토어에 배포하세요. 가지고 있는 Script 중 가장 단순한 것을 고르세요. 보통 결제 수단 숨김 규칙입니다. 처음부터 끝까지 이전해 보세요. 프로덕션에 적용하지 않더라도 개발 도구가 제대로 작동하는지 확인할 수 있습니다.
4. 앞으로 8주간의 작업 시간을 일정에 확보하세요. 이전 작업은 스프린트 사이의 남는 시간에 끝나지 않습니다. 예를 들어 매주 화요일과 목요일 오후에 반복 일정을 잡고, 배포 일정처럼 다루세요.
이전한 팀들에서 본 흐름은 비슷합니다. 시작을 미루는 데 2주, 실제 작업에 3주, 정리에 1주가 걸립니다. 합계 6주입니다. 지금은 10주가 있습니다. 남는 시간은 시작을 미루는 데 쓰지 말고 코드 검토와 품질 확인에 쓰세요.
결제(체크아웃) 로직을 정리한 뒤에는 대부분 구매 후 주문 수정을 다룹니다. 고객의 주소 변경, 상품 교체, 주문 완료 후 할인 추가 같은 작업입니다. 주문량이 많은 Plus 운영 스토어든 고객 경험을 중시하는 Advanced 스토어든 이 작업이 계획에 있다면, Shopify App Store에서 Revize를 확인하세요. Revize는 여기서 구축할 모든 Function과 함께 작동합니다.
자료
- Shopify Functions 개요 — Shopify Developer Docs
- Shopify Scripts에서 Functions로 이전하기
- Discount Function 구축 튜토리얼
- Delivery Customization Function API 참고 문서
- Payment Customization Function API 참고 문서
- Shopify CLI 문서
2026년 8월 업데이트. Revize는 고객이 구매 후 자신의 주문을 직접 수정할 수 있게 하는 Shopify 앱입니다. 고객은 지원 요청을 하지 않고도 주문 처리(풀필먼트) 전에 배송 주소를 변경하고, 옵션이나 상품을 교체하고, 주문을 취소하고, 환불이나 스토어 크레딧을 받을 수 있습니다. 고객이 자신의 Shopify 주문을 직접 수정하도록 하는 방법을 자세히 알아보거나 Shopify App Store에서 Revize를 확인하세요.