- 들어가며 — 발표 글 없이, npm에 먼저 올라왔다
- 타임라인 — 2.x가 어디까지 달려왔는지 먼저
- v3가 올리는 바닥 — 런타임과 툴체인 최소선
- 지워지는 API — 2년 치 폐기 예고의 청산
- 조용히 바뀌는 기본값 — 보안 쪽이 많다
- 여전히 experimental인 것 — v3는 기능 메이저가 아니다
- 옆 동네와의 대조 — 메이저가 하는 일이 다르다
- 그래서 지금 무엇을 해야 하나
- 마치며
- 참고 자료
들어가며 — 발표 글 없이, npm에 먼저 올라왔다
svelte.dev 블로그에 "SvelteKit 3을 소개합니다" 같은 글은 아직 없습니다. 대신 npm 레지스트리에는 이미 흔적이 선명합니다 — @sveltejs/kit의 3.0.0-next.0이 2026년 6월 5일에 올라왔고, 이 글을 쓰는 시점(2026-07-17) 기준 최신 프리릴리스는 7월 14일의 3.0.0-next.8입니다. 6주가 채 안 되는 기간에 아홉 번의 프리릴리스가 나왔고, 안정판 2.69.3(7월 13일)과 나란히 두 트랙으로 릴리스가 돌고 있습니다.
저장소 쪽 증거도 같습니다. sveltejs/kit에는 version-3 브랜치가 열려 있고, 3.0 마일스톤은 오늘 기준 닫힌 이슈 107개, 열린 이슈 27개입니다. 정식 출시일은 발표된 바 없습니다 — 그러니 이 글의 내용도 "next.8 시점의 스냅샷"으로 읽어야 합니다. 프리릴리스니까 여기서 또 바뀔 수 있습니다.
그런데 version-3 브랜치의 체인지로그를 next.0부터 next.8까지 통독하면 한 가지가 분명해집니다. 이 메이저에는 새 기능이 거의 없습니다. 대신 2년 치 폐기 예고를 청산하고, 툴체인 바닥을 올리고, 기본값을 조입니다. 그리고 커뮤니티가 SvelteKit 3의 얼굴로 기대하는 것들 — remote functions, 컴포넌트 안의 await — 은 v3 프리릴리스에서도 여전히 experimental입니다. 이 구도를 이해하는 것이 마이그레이션 판단의 절반입니다.
타임라인 — 2.x가 어디까지 달려왔는지 먼저
v3를 읽으려면 2.x 후반의 흐름을 알아야 합니다. 날짜는 전부 npm 레지스트리의 publish 시각 기준입니다.
2024-12-16 kit 2.12 $app/state 추가 (룬 기반 — $app/stores의 후임)
2025-07-14 svelte 5.36 컴포넌트 await (experimental.async 플래그)
2025-07-24 kit 2.26 $app/paths에 resolve()/asset() 추가 (옛 base/assets 대체)
2025-07-31 kit 2.27 remote functions (experimental 플래그)
2026-01-22 svelte 5.48 ← 나중에 kit v3의 최소 Svelte 버전이 되는 릴리스
2026-05-01 kit 2.59 query.live 추가 (experimental)
2026-05-22 kit 2.61 query.live async iterable화, 쿼리 .run() 제거(파괴적)
2026-06-02 kit 2.62 svelte.config.js 없이 Vite 플러그인에 설정 전달 가능
2026-06-04 kit 2.63 명시적 환경 변수 (experimental)
2026-06-05 kit 3.0.0-next.0 ← 프리릴리스 시작
2026-07-14 kit 3.0.0-next.8 ← 현재
두 가지가 눈에 띕니다. 첫째, 2.62와 2.63은 v3 직전에 나온 "예고편"입니다 — 7월 다이제스트의 표현을 빌리면 설정의 vite.config 이동과 명시적 환경 변수는 둘 다 "Kit 3에서 이렇게 된다는 프리뷰"로 2.x에 먼저 실렸습니다. 둘째, 2.61에서 보듯 experimental 딱지가 붙은 기능은 마이너 릴리스에서도 파괴적 변경이 계속 일어납니다. .run() 제거, requested(...) 시그니처 변경 같은 것들이 semver 마이너로 나왔습니다 — 플래그를 켰다면 semver가 지켜 주지 않는 구역에 들어간 것입니다.
v3가 올리는 바닥 — 런타임과 툴체인 최소선
next.0의 체인지로그가 못 박는 최소 요구사항입니다.
- Node 22 이상 (#12548)
- TypeScript 6 이상 (#15930) — npm에는 6.0.2·6.0.3 안정판이 있고, 그 위로 TypeScript 7.0이 이미 GA(7.0.2, 2026-07-08)입니다. 참고로 svelte-check 4.7.0에는 tsgo(네이티브 TS) 지원이 experimental로 들어와 있습니다.
- Vite 8 — 처음에는 Vite 8 요구(#15371)였다가, next.5에서
vite@^8.0.12로 조여졌습니다. 체인지로그 문구 그대로 옮기면 "안정판 rolldown 1.0.0을 번들한 첫 Vite 8 릴리스"이기 때문입니다(#16134). npm 날짜로 교차 확인하면 rolldown 1.0.0이 2026-05-07, vite 8.0.12가 2026-05-11 — 나흘 차이로 맞물립니다. 즉 SvelteKit 3은 Rust 번들러 위에서만 돕니다. - @sveltejs/vite-plugin-svelte 7 (#15371)
- Svelte 5.48.0 이상 — 여기가 중요합니다. Svelte 6이 아닙니다. 5.48은 2026년 1월에 나온 평범한 마이너입니다. v3는 Svelte의 세대 교체와 커플링되어 있지 않습니다.
체인지로그는 Vite 8 요구의 근거로 "Vite hook filter를 통한 더 빠른 빌드와 Vite environment API를 쓰는 더 강력한 어댑터"를 듭니다 — 구체적인 빌드 시간 수치는 어디에도 공개된 것이 없으므로, 여기서는 프로젝트 자신의 표현이라는 것만 적어 둡니다.
지워지는 API — 2년 치 폐기 예고의 청산
v3에서 제거되거나 이름이 바뀌는 것들입니다. 전부 후임 API가 2.x에 먼저 들어와 있던 것들이라, "갑작스러운 제거"는 사실상 없습니다.
| 사라지는 것 | 후임 | 후임이 들어온 시점 |
|---|---|---|
$app/stores 모듈 전체 (#15499) | $app/state | kit 2.12 (2024-12) |
$app/paths의 base·assets·resolveRoute (#15507) | resolve()·asset() | kit 2.26 (2025-07) |
invalidateAll (deprecated) (#16289) | refreshAll (goto 옵션에도 적용) | v3 next.8에서 신설 |
$app/environment | $app/env로 개명 (별칭은 유지, next.1) | v3 |
$env/* 4종 모듈 | 명시적 환경 변수 ($app/env/private·$app/env/public) | kit 2.63 (experimental) |
svelte.config.js 필수 | Vite 플러그인에 설정 전달 (#16007) | kit 2.62부터 가능 |
| 폴더 안의 param 파일 | params.js/ts 단일 파일 (#16189) | v3 |
preloadStrategy 옵션 | 항상 modulepreload + output.linkHeaderPreload | v3 |
CSRF checkOrigin | trustedOrigins | kit 2.x에서 이미 deprecated |
@sveltejs/kit/node/polyfills, 어댑터용 createEntries | 없음 (제거) | — |
몇 가지 짚을 점이 있습니다.
$app/stores의 제거는 룬 전환의 마침표입니다. Svelte 5 룬이 스토어를 밀어낸 지 오래지만, SvelteKit의 page·navigating·updated 스토어는 하위 호환 때문에 살아 있었습니다. 후임 $app/state가 나온 지 1년 반이 지났으니 청산 시점으로는 온건한 편입니다.
invalidateAll → refreshAll은 어휘 통일입니다. PR #16289를 읽어 보면 의도가 드러납니다 — remote functions 세계에서 데이터 갱신은 query.refresh()이고, load 함수 세계의 "무효화"와 용어가 갈라져 있었습니다. refreshAll은 그 둘을 한 단어로 모으는 이름이고, load 함수를 항상 다시 실행하도록 옵션도 정리됐습니다. 주의할 점: refreshAll은 2.69.3에는 없습니다. v3로 올라갈 때 바꾸면 되는 일이지, 오늘 할 수 있는 일은 아닙니다.
환경 변수는 모듈 마법에서 명시적 선언으로 갑니다. 문서의 예고 문구는 명확합니다 — 명시적 환경 변수가 v3의 기본이 되고, $env/* 모듈과 $app/environment는 제거됩니다. 새 방식은 src/env.ts에서 선언합니다.
// src/env.ts — kit 2.63+에서 experimental.explicitEnvironmentVariables로 미리 써 볼 수 있다
import { defineEnvVars } from '@sveltejs/kit/hooks';
export const variables = defineEnvVars({
API_KEY: {}, // 기본은 private — $app/env/private로만 임포트 가능
});
지금까지 $env/static/private가 "임포트 위치로 노출 여부를 강제"하는 영리한 장치였다면, 새 방식은 앱에 존재하는 환경 변수의 목록 자체를 한 파일에 타입과 함께 못 박습니다. 어떤 변수가 있는지 코드만 봐서는 알 수 없던 문제가 사라지는 대신, 변수 하나 추가할 때마다 선언이 한 줄 늘어납니다.
조용히 바뀌는 기본값 — 보안 쪽이 많다
제거보다 조용하지만 실제로 동작이 달라지는 것들입니다. 마이그레이션에서 시간을 잡아먹는 건 보통 이쪽입니다.
- 외부 리다이렉트가 기본 금지됩니다 (#16198). 외부 URL(그리고
javascript:URL)로redirect하려면 이제external옵션을 명시적으로 넘겨야 합니다. 로그인 후?next=파라미터로 리다이렉트하는 코드가 있다면 — open redirect의 단골 자리인데 — v3에서 그대로 두면 깨집니다. 깨지는 게 의도입니다. - 쿠키 기본
path가'/'가 됩니다 (#15398). 지금까지는 현재 경로 기준이었고, 이게 "쿠키를 설정했는데 다른 페이지에서 안 보인다"는 단골 질문의 원인이었습니다. cookie v1 채택으로 쿠키 이름도 ASCII로 제한됩니다(#13386). - form action 실패가
fail()에 담은 HTTP 상태 코드를 실제 응답 코드로 씁니다 (#16200). 지금까지 성공 200에 실려 오던 것이 바뀌므로, 상태 코드를 보고 동작하는 프록시·모니터링이 있다면 영향을 받습니다. 204 응답은 정말로 본문 없이 나갑니다. handleError가 응답 상태 코드에 영향을 줄 수 있게 됩니다 (#16162).goto가 앱 라우트로 해석되지 않는 URL에서 reject합니다 (#16164) — 외부 URL에서 이미 그랬던 것과 동작을 맞췄습니다.- 내비게이션 중
invalidate호출이 내비게이션을 중단시키지 않습니다 (#16188).
참고로 remote functions 응답에 cache-control: private, no-store를 강제해 개인화된 쿼리 결과가 공유 캐시에 남지 않게 하는 수정은 v3가 아니라 2.65.2에 이미 들어갔습니다 — 보안 기본값 조이기는 v3 전용 테마가 아니라 최근 몇 달의 일관된 방향입니다.
여전히 experimental인 것 — v3는 기능 메이저가 아니다
여기가 이 글에서 가장 중요한 절입니다.
Remote functions는 v3에서도 experimental입니다. 공식 문서는 지금도 "currently experimental… subject to change without notice"라고 적혀 있고, kit.experimental.remoteFunctions와 compilerOptions.experimental.async 두 플래그를 요구합니다. 더 시사적인 건 v3 프리릴리스의 방향입니다 — next.7은 오히려 플래그 없이 *.remote.ts/js 파일을 두는 것을 금지했습니다(#16247, 2026-07-07 머지). 안정화가 임박했다면 나올 수 없는 변경입니다. 2.27로 2025년 7월에 나와 1년 가까이 지나도록, 그리고 v3 메이저를 넘어서도, remote functions의 API 안정성 보장은 없습니다.
컴포넌트 await도 마찬가지입니다. Svelte 5.36(2025-07-14)부터 experimental.async 플래그로 써 왔고, 문서는 플래그가 제거되는 시점을 명시합니다 — "The experimental flag will be removed in Svelte 6." 그리고 Svelte 6은 npm에 존재하지 않습니다 — 6.x는 정식판도 프리릴리스도 발행된 적이 없고, svelte의 latest는 5.56.6(2026-07-16)입니다. kit v3의 최소 요구가 Svelte 5.48인 것이 이 구도를 요약합니다: SvelteKit의 메이저와 Svelte의 메이저는 분리된 열차입니다. 컴파일러 쪽의 experimental 목록에는 fork API(5.42)와 async SSR(5.39)도 그대로 남아 있습니다.
반대 방향의 졸업도 하나 있습니다 — OpenTelemetry 트레이싱은 next.7에서 experimental 네임스페이스를 벗어나 정식 API가 됐습니다(#16260).
정리하면 v3의 정체는 이렇습니다. 화제성 있는 기능은 전부 experimental 트랙에서 2.x와 v3에 동시에 실려 가고, 메이저 버전은 그 밑의 바닥 — 런타임, 번들러, 이름, 기본값 — 을 갈아 끼우는 데 쓰입니다. "v3로 올리면 remote functions가 안정된다"는 기대는 현재 증거로는 성립하지 않습니다.
옆 동네와의 대조 — 메이저가 하는 일이 다르다
같은 주에 React 생태계를 달군 뉴스가 React Compiler의 Rust 포팅이었다는 점은 대조가 흥미롭습니다. React는 수동 메모이제이션을 없애기 위해 컴파일러 인프라를 새로 짓는 중이고 — 그것도 실험적 WIP 단계 — Svelte는 처음부터 컴파일러가 프레임워크였으니 그 단계가 없습니다. 대신 Svelte 쪽 메이저는 번들러(rolldown)와 런타임 바닥을 올리는 데 쓰입니다. 2026년의 두 프레임워크 모두 "새 기능 대방출"이 아니라 기반 공사에 메이저급 에너지를 쓰고 있다는 공통점이 있고, 어느 쪽도 당장 앱 개발자의 코드를 크게 바꾸지 않습니다.
그래서 지금 무엇을 해야 하나
오늘 2.x에서 미리 할 수 있는 것 — 전부 v3 마이그레이션의 선불입니다.
$app/stores임포트를$app/state로 옮깁니다. 1년 반 된 API라 레퍼런스도 충분합니다.$app/paths의base·assets문자열 결합을resolve()·asset()으로 바꿉니다.- 설정을
vite.config의 플러그인 옵션으로 옮겨 봅니다(2.62+). 새 프로젝트라면 sv CLI 0.16이 이미 그렇게 스캐폴딩합니다. - Node 22, Vite 8, vite-plugin-svelte 7로 먼저 올라가 봅니다 — 이건 v3 없이도 지금 가능한 검증입니다.
invalidateAll사용처를 파악해 둡니다. 바꾸는 건 v3에서지만, 어디서 쓰는지 아는 건 지금 됩니다.
하지 말아야 할 것.
3.0.0-next.*를 프로덕션에 올리는 것. 프리릴리스는 next.8까지 오는 동안에도 파괴적 변경이 계속 나왔습니다($app/stores제거는 next.7,refreshAll은 next.8에 나왔습니다).- remote functions를 안정 API로 간주하고 팀 표준이나 공개 라이브러리를 세우는 것. 2.61의
.run()제거 같은 일이 또 일어나지 않는다는 보장이 없습니다 — experimental의 정의가 그것입니다. - "Svelte 6 나오면 한꺼번에"라며 v3 대비를 미루는 것. 위에서 봤듯 두 메이저는 분리돼 있어서, 기다림의 대상이 서로 다릅니다.
어댑터·라이브러리 저자라면 일이 더 있습니다. createEntries가 사라지고, 어댑터가 Vite 플러그인을 직접 제공할 수 있게 되며(#16206), Vite environment API 기반으로 어댑터가 재편됩니다. 앱 코드보다 이쪽 생태계가 v3 출시 시점의 실질적 병목이 될 가능성이 높습니다.
마치며
SvelteKit 3.0 프리릴리스의 체인지로그는 화려하지 않습니다. 그리고 그게 좋은 신호라고 생각합니다. 재학습을 요구하는 메이저 — 라우터가 바뀌고 데이터 로딩 모델이 바뀌는 종류 — 가 아니라, 폐기 예고를 이행하고 바닥을 올리고 기본값을 조이는 메이저입니다. 룬을 다시 배울 필요도, load 함수를 다시 쓸 필요도 없습니다.
대신 기대치는 정확히 잡아야 합니다. remote functions와 컴포넌트 await가 "정식"이 되는 사건은 SvelteKit 3이 아닙니다 — 전자는 아직 기약이 없고, 후자는 문서상 Svelte 6의 일입니다. v3는 그 미래가 올라설 바닥(rolldown 기반 Vite 8, Node 22, 정리된 API 표면)을 까는 릴리스로 읽는 것이 체인지로그와 일치하는 독해입니다. 프리릴리스가 진행 중이므로, 정식 출시 때 이 글의 세부 사항 일부는 달라져 있을 수 있습니다 — 그때 다시 확인할 것을 전제로 쓰는 스냅샷입니다.
참고 자료
- @sveltejs/kit CHANGELOG (version-3 브랜치) — 3.0.0-next.0~next.8 전체 변경 사항
- npm: @sveltejs/kit 버전 목록 — 프리릴리스 발행 일자 확인
- PR #16289 — invalidateAll deprecation과 refreshAll
- PR #16198 — 외부 리다이렉트 기본 금지
- PR #16247 — 플래그 없는 remote 파일 금지
- PR #15507 — $app/paths의 base/assets/resolveRoute 제거
- SvelteKit 문서: Remote functions — experimental 고지와 플래그
- Svelte 문서: await expressions — "The experimental flag will be removed in Svelte 6"
- SvelteKit 문서: Environment variables — 명시적 환경 변수와 v3 예고
- What's new in Svelte: July 2026 — config-in-vite와 명시적 env의 "Kit 3 프리뷰" 설명
- What's new in Svelte: June 2026 — query.live와 2.x 내 파괴적 변경들
- Svelte 5 룬 심층 — 반응성 재설계 배경(관련 글)
- React Compiler Rust 포팅 — 옆 동네 메이저 작업과의 대조(관련 글)
- TypeScript 7 GA — kit v3의 TS 최소 요구와 얽히는 배경(관련 글)
현재 단락 (1/86)
svelte.dev 블로그에 "SvelteKit 3을 소개합니다" 같은 글은 아직 없습니다. 대신 npm 레지스트리에는 이미 흔적이 선명합니다 — [`@sveltejs/kit`](...