diff --git a/apps/web-mobile/bun.lock b/apps/web-mobile/bun.lock
index 4931870e..1bdb60bd 100644
--- a/apps/web-mobile/bun.lock
+++ b/apps/web-mobile/bun.lock
@@ -37,8 +37,8 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-i18next": "^15.4.0",
- "react-router": "^7.1.3",
- "react-router-dom": "^7.1.3",
+ "react-router": "^7.6.3",
+ "react-router-dom": "^7.6.3",
"recharts": "^2.15.1",
"styletron-engine-monolithic": "^1.0.0",
"styletron-react": "^6.1.1",
@@ -457,8 +457,6 @@
"@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="],
- "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
-
"@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="],
"@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
@@ -1153,9 +1151,9 @@
"react-range": ["react-range@1.10.0", "", { "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-kDo0LiBUHIQIP8menx0UoxTnHr7UXBYpIYl/DR9jCaO1o29VwvCLpkP/qOTNQz5hkJadPg1uEM07XJcJ1XGoKw=="],
- "react-router": ["react-router@7.1.3", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0", "turbo-stream": "2.4.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA=="],
+ "react-router": ["react-router@7.6.3", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-zf45LZp5skDC6I3jDLXQUu0u26jtuP4lEGbc7BbdyxenBN1vJSTA18czM2D+h5qyMBuMrD+9uB+mU37HIoKGRA=="],
- "react-router-dom": ["react-router-dom@7.1.3", "", { "dependencies": { "react-router": "7.1.3" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-qQGTE+77hleBzv9SIUIkGRvuFBQGagW+TQKy53UTZAO/3+YFNBYvRsNIZ1GT17yHbc63FylMOdS+m3oUriF1GA=="],
+ "react-router-dom": ["react-router-dom@7.6.3", "", { "dependencies": { "react-router": "7.6.3" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-DiWJm9qdUAmiJrVWaeJdu4TKu13+iB/8IEi0EW/XgaHCjW/vWGrwzup0GVvaMteuZjKnh5bEvJP/K0MDnzawHw=="],
"react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="],
@@ -1293,8 +1291,6 @@
"tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="],
- "turbo-stream": ["turbo-stream@2.4.0", "", {}, "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g=="],
-
"tween-functions": ["tween-functions@1.2.0", "", {}, "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
diff --git a/apps/web-mobile/package.json b/apps/web-mobile/package.json
index cfd7a3fd..610e5a94 100644
--- a/apps/web-mobile/package.json
+++ b/apps/web-mobile/package.json
@@ -47,8 +47,8 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-i18next": "^15.4.0",
- "react-router": "^7.1.3",
- "react-router-dom": "^7.1.3",
+ "react-router": "^7.6.3",
+ "react-router-dom": "^7.6.3",
"recharts": "^2.15.1",
"styletron-engine-monolithic": "^1.0.0",
"styletron-react": "^6.1.1",
diff --git a/apps/web/.gitignore b/apps/web/.gitignore
index be5bf931..2ec3b782 100644
--- a/apps/web/.gitignore
+++ b/apps/web/.gitignore
@@ -31,4 +31,6 @@ dist-ssr
.env
.env.prod
-.env.local
\ No newline at end of file
+.env.local
+
+.tanstack
\ No newline at end of file
diff --git a/apps/web/package.json b/apps/web/package.json
index bdb70fae..d1852289 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -37,7 +37,10 @@
"@tailwindcss/vite": "^4.1.4",
"@tanstack/react-query": "^5.76.0",
"@tanstack/react-query-devtools": "^5.76.0",
+ "@tanstack/react-router": "^1.125.4",
+ "@tanstack/react-router-devtools": "^1.125.4",
"@tanstack/react-table": "^8.21.2",
+ "@tanstack/zod-adapter": "^1.125.4",
"@types/numeral": "^2.0.5",
"@vitest/ui": "^3.0.4",
"axios": "^1.7.9",
@@ -58,8 +61,6 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
"react-i18next": "^15.4.0",
- "react-router": "^7.1.3",
- "react-router-dom": "^7.1.3",
"recharts": "^2.15.1",
"styletron-engine-monolithic": "^1.0.0",
"styletron-react": "^6.1.1",
@@ -79,6 +80,7 @@
"@storybook/react": "^8.5.2",
"@storybook/react-vite": "^8.5.2",
"@storybook/test": "^8.5.2",
+ "@tanstack/router-plugin": "^1.125.4",
"@types/lodash": "^4.17.15",
"@types/ramda": "^0.30.2",
"@types/react": "^18.3.18",
diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx
deleted file mode 100644
index ba582ddb..00000000
--- a/apps/web/src/App.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import { useAtomValue } from "jotai";
-import { useEffect } from "react";
-import { BrowserRouter, Route, Routes } from "react-router-dom";
-import { themeAtom } from "./atoms/theme";
-import AlbumPage from "./pages/album";
-import ApiKeys from "./pages/apikeys";
-import ArtistPage from "./pages/artist";
-import Dropbox from "./pages/dropbox";
-import DropboxWithId from "./pages/dropbox/DropboxWithId";
-import GoogleDrive from "./pages/googledrive";
-import GoogleDriveWithId from "./pages/googledrive/GoogleDriveWithId";
-import HomePage from "./pages/home";
-import Loading from "./pages/loading";
-import PlaylistPage from "./pages/playlist";
-import ProfilePage from "./pages/profile";
-import SongPage from "./pages/song";
-
-function App() {
- const { darkMode } = useAtomValue(themeAtom);
- useEffect(() => {
- const root = document.getElementById("root");
- if (darkMode) {
- root!.classList.add("dark");
- return;
- }
- root!.classList.remove("dark");
- }, [darkMode]);
-
- return (
-