헤드리스 스토어프론트, '쉽게 배포'는 됐지만 '이식 가능'하진 않았다
Hydrogen은 헤드리스 스토어프론트를 만드는 일을 확실히 쉽게 만들어줬어요. 문제는 그게 특정 런타임에 묶여버린다는 점이었죠. Vercel Ship 26에서 발표된 내용에 따르면, Vercel과 Shopify는 Hydrogen을 처음부터 다시 만드는(rebuild from the ground up) 공동 작업에 들어갑니다. 키워드는 세 가지입니다.
- 오픈소스: 코드가 열려 있습니다.
- 런타임 불가지론(Runtime Agnostic): JavaScript가 도는 곳이면 어디든 실행됩니다.
- 프레임워크 자유: Svelte, Nuxt, Next.js는 물론 커스텀 프레임워크도 가능합니다.
전략은 Core / Client / Server 3계층으로 나뉩니다. 각 계층이 어떤 '반복 노동'을 제거하는지가 이 글의 핵심이에요.
근거자료: Vercel 공식 블로그 — Vercel and Shopify are rebuilding Hydrogen
국내 SI·커머스 환경에서는 이 변화가 특히 반갑습니다. 그동안 Shopify Headless를 도입하려면 '런타임 종속' 리스크를 감수해야 했는데, 이제 Next.js 기반 자체 인프라에 얹는 선택지가 현실화됐어요.

Core 계층 — '우리가 매번 다시 쓰던 그 코드'를 한 곳에 모은다
가장 명확한 예시는 금액 포맷팅입니다. 웹 표준만 쓰면 이렇게 끝나죠.
// 표준 Intl API로 USD 포맷팅
const price = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(19.99); // "$19.99"
그런데 Shopify API는 순수한 number를 주지 않습니다. MoneyV2라는 커스텀 타입으로 응답하고, amount는 문자열로 직렬화된 부호 있는 십진수예요. 그래서 다들 이런 글루 코드를 직접 짰습니다.
import { formatMoney, type MoneyV2 } from "@shopify/hydrogen";
// Core 계층이 제공하는 포맷터 — 글루 코드 유지보수 끝
export function formatPrice(money: MoneyV2, locale = "en-US") {
return formatMoney(money, { locale }).toString(); // $19.99
}
결과는 같지만, 이제 글루 코드를 직접 쓰거나 유지보수하지 않습니다. API 스펙이 바뀌면 업그레이드 한 번이면 끝이에요. Core를 중앙화하면 버그는 한 번만 고치면 되고, 개선사항은 모든 사용자에게 자동 배포됩니다.
Client 계층 — 장바구니 상태 관리는 이제 import 한 줄
장바구니 상태는 커머스 앱을 만든 사람이라면 누구나 한 번은 직접 짜봤을 겁니다.
// 기존 방식: 매번 다르게, 매번 반복
import { createContext, useContext, useState, useCallback } from "react";
const CartContext = createContext(null);
export function CartProvider({ children }) {
const [cart, setCart] = useState(null);
const addLine = useCallback(async (variantId, quantity) => {
// 우리 모두가 직접 짰던 커스텀 코드
}, []);
// applyDiscount, note, currency, error state, cross-tab sync, refetch on focus...
return ({children});
}
export const useCart = () => useContext(CartContext);
문제는 매번 다른 코드, 그러나 추구하는 목표는 동일하다는 점입니다. Hydrogen의 Client 계층은 이걸 단일 import로 처리해요.
// Hydrogen 방식: 장바구니 상태 관리가 import 한 줄
import { createCartComponents } from "@shopify/hydrogen/react";
const { useCartForm } = createCartComponents();
function AddToCartButton({ variantId }) {
const { formProps, register } = useCartForm();
return (
<form {...formProps}>
<input type="hidden" {...register("variantId")} value={variantId} />
<button type="submit">Add to cart</button>
</form>
);
}
장바구니 상태 관리를 베스트 프랙티스 그대로 공짜로 얻는 셈입니다. 지금은 React용으로 Hydrogen preview 브랜치에서 사용 가능하고, 다른 프레임워크도 순차 지원 예정이에요.

Server 계층 — 풀스택 프레임워크 위에 Shopify API를 얹는다
스토어프론트가 성능을 희생하지 않고 확장되려면 풀스택 접근이 필요합니다. 정적 콘텐츠는 CDN에서 즉시, 재고 같은 동적 데이터는 스트리밍으로요.
오픈소스 커뮤니티는 이미 이걸 Next.js, Nuxt, SvelteKit으로 해결했습니다. 독점 런타임에 종속되지 않는 풀스택 역량이죠.
// Next.js + Hydrogen: 타입 안전 클라이언트 + 온디맨드 재검증
import { PRODUCT_QUERY } from "@/lib/gql";
import { storefrontConfig } from "@/lib/config";
import { cacheTag } from "next/cache";
import { createStorefrontClient } from "@shopify/hydrogen";
// 온디맨드로 재검증 가능한 상품 데이터 캐시 함수
export async function getProductData({ handle }) {
"use cache";
cacheTag(handle);
const client = createStorefrontClient({
type: "private_shared_rate_limit",
config: storefrontConfig,
});
const { data } = await client.graphql(PRODUCT_QUERY, {
variables: { handle },
});
return data;
}
Shopify는 이미 Headless sales channel로 이 프레임워크들을 지원하지만, 지금까지는 모두가 각자 동일한 API 계약에 대한 바인딩을 직접 작성했습니다. 이 계층의 해법은 '더 많은 코드'가 아니라 가이던스입니다. 사람과 에이전트 모두, 프레임워크가 이미 하는 일을 재발명하지 말고 그대로 쓰도록 안내해야 하죠. 이 가이던스는 문서·템플릿·스킬 형태로 배포됩니다.
⚠️ 실무 주의: Cache Components 호환성 함정
Next.js 16의 cacheComponents: true 환경에서 i18n을 붙일 때, 아래 함정을 모르면 전혀 무관해 보이는 빌드 에러가 쏟아집니다.
| 함정 | 증상 | 대응 |
|---|---|---|
app/layout.tsx가 app/[locale]/ 위에 존재 | rootParams.locale()이 undefined 반환 | 루트 레이아웃을 app/[locale]/layout.tsx로 이동, 원본 삭제 |
setRequestLocale 사용 | 캐시 무력화, 강제 동적 렌더링 | next/root-params 기반 getLocale()로 대체 |
next-intl Link로 전면 교체 | unstable_samples 미정의 에러 | next/link 유지, middleware가 프리픽스 리다이렉트 |
instant 샘플에 locale 누락 | 루트 파라미터 미정의 빌드 실패 | 모든 샘플 params에 locale 추가 |
레이아웃에서 headers() 읽음 | 헤더 미정의 빌드 실패 | 샘플에 headers: [["x-vercel-ip-postal-code", null]] 추가 |
특히 마지막 항목은 배송 지역 배너 같은 컴포넌트 하나만 추가해도 앱 전체 instant 샘플을 손봐야 하니, 레이아웃 레벨 서버 컴포넌트 추가는 신중히 결정하세요.
vercel.shop과의 관계
Hydrogen 이전에도 Vercel은 자체 템플릿 vercel.shop을 운영했습니다. Next.js + Shopify 조합을 쉽게 만들어주는 물건이었죠. 이번 재구축은 그 경험을 Client/Server 계층에 흡수시키는 작업입니다. Hydrogen이 안정화되면 vercel.shop이 이를 채택해서 Next.js + Hydrogen 레퍼런스로 자리 잡습니다.

정리 — '런타임 락인'을 걷어낸다는 것
이번 재구축의 본질은 기능 추가가 아니라 종속성 제거입니다. Core는 반복 코드를 한 곳에 모으고, Client는 장바구니 같은 상투적 상태 관리를 흡수하고, Server는 프레임워크의 풀스택 역량을 그대로 씁니다.
함께 보면 좋은 글
- "에이전트 스킬·MCP, 이제 플러그인 하나로 통합한다 — Agent Plugins 1.0.0 완전 해부" — 이번 Hydrogen의 'skills' 배포 전략과 정확히 같은 흐름입니다.
- "개인화와 실험은 왜 별도의 기술 스택이 필요한가? (스포티파이의 인사이트)" — '관심사 분리' 관점에서 이번 3계층 전략을 다시 읽어보면 인사이트가 배가 됩니다.
다음 단계 학습 방향
- Next.js 16 Cache Components 문서를 먼저 훑으세요.
use cache,cacheTag,instant샘플 개념을 모르면 위 함정들이 그냥 마법처럼 보입니다. - next-intl + App Router 조합을 작은 프로젝트에서 직접 붙여보세요.
rootParams패턴은 앞으로 표준이 될 가능성이 높습니다. - Hydrogen preview 브랜치를 fork해서 React용 Client 계층을 먼저 체험해보세요. 커스텀 프레임워크 지원이 나오기 전에 감을 잡아두면 유리합니다.
국내 커머스 팀이라면, 지금 당장 프로덕션 도입보다는 사이드 프로젝트 수준에서 Hydrogen + Next.js 조합을 검증해두는 걸 권합니다. 런타임 종속이 사라진다는 건 곧 '우리 인프라에 맞게 조정할 여지'가 생긴다는 뜻이니까요. 😄