diff --git a/apps/timo-web/app/[locale]/layout.tsx b/apps/timo-web/app/[locale]/layout.tsx
index 1172807c..cfcd590e 100644
--- a/apps/timo-web/app/[locale]/layout.tsx
+++ b/apps/timo-web/app/[locale]/layout.tsx
@@ -12,6 +12,7 @@ import { AuthProvider } from "@/providers/auth/AuthProvider";
import { LanguageSyncProvider } from "@/providers/locale/LanguageSyncProvider";
import { OverlayProvider } from "@/providers/overlay/OverlayProvider";
import { QueryProvider } from "@/providers/query/QueryProvider";
+import { ServiceWorkerCleanup } from "@/providers/service-worker/ServiceWorkerCleanup";
const pretendard = localFont({
src: "../../fonts/PretendardVariable.woff2",
@@ -106,6 +107,7 @@ export default async function RootLayout({
return (
+
diff --git a/apps/timo-web/providers/service-worker/ServiceWorkerCleanup.tsx b/apps/timo-web/providers/service-worker/ServiceWorkerCleanup.tsx
new file mode 100644
index 00000000..c3723d58
--- /dev/null
+++ b/apps/timo-web/providers/service-worker/ServiceWorkerCleanup.tsx
@@ -0,0 +1,26 @@
+"use client";
+
+import { useEffect } from "react";
+
+/**
+ * 도메인 이전 전 PWA로 설치됐던 구버전 서비스워커가 사용자 브라우저에 남아
+ * 캐시된 구버전 페이지를 계속 서빙하는 문제를 막기 위해,
+ * 현재 origin에 등록된 서비스워커와 캐시를 전부 정리한다.
+ */
+export const ServiceWorkerCleanup = () => {
+ useEffect(() => {
+ if (!("serviceWorker" in navigator)) return;
+
+ navigator.serviceWorker.getRegistrations().then((registrations) => {
+ registrations.forEach((registration) => registration.unregister());
+ });
+
+ if (!("caches" in window)) return;
+
+ caches.keys().then((keys) => {
+ keys.forEach((key) => caches.delete(key));
+ });
+ }, []);
+
+ return null;
+};