diff --git a/.ci/android.sh b/.ci/android/build.sh
similarity index 79%
rename from .ci/android.sh
rename to .ci/android/build.sh
index a92e1a0ae8..eaeff11472 100755
--- a/.ci/android.sh
+++ b/.ci/android/build.sh
@@ -1,5 +1,8 @@
 #!/bin/bash -e
 
+# SPDX-FileCopyrightText: 2025 eden Emulator Project
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 export NDK_CCACHE=$(which ccache)
 
 # keystore & pass are stored locally
diff --git a/.ci/android/package.sh b/.ci/android/package.sh
new file mode 100755
index 0000000000..c2eb975a02
--- /dev/null
+++ b/.ci/android/package.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# SPDX-FileCopyrightText: 2025 eden Emulator Project
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+GITDATE="$(git show -s --date=short --format='%ad' | sed 's/-//g')"
+GITREV="$(git show -s --format='%h')"
+ARTIFACTS_DIR="$PWD/artifacts"
+mkdir -p "${ARTIFACTS_DIR}/"
+
+REV_NAME="eden-android-${GITDATE}-${GITREV}"
+BUILD_FLAVOR="mainline"
+BUILD_TYPE_LOWER="release"
+BUILD_TYPE_UPPER="Release"
+
+cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \
+	"${ARTIFACTS_DIR}/${REV_NAME}.apk" || echo "APK not found"
+
+cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \
+	"${ARTIFACTS_DIR}/${REV_NAME}.aab" || echo "AAB not found"
+
+ls -la "${ARTIFACTS_DIR}/"
diff --git a/.ci/linux.sh b/.ci/linux/build.sh
similarity index 95%
rename from .ci/linux.sh
rename to .ci/linux/build.sh
index 694e1c5b2a..f620cd1ecb 100755
--- a/.ci/linux.sh
+++ b/.ci/linux/build.sh
@@ -1,5 +1,8 @@
 #!/bin/bash -ex
 
+# SPDX-FileCopyrightText: 2025 eden Emulator Project
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 export ARCH="$(uname -m)"
 
 if [ "$ARCH" = 'x86_64' ]; then
diff --git a/.ci/eden.dwfsprof b/.ci/linux/eden.dwfsprof
similarity index 100%
rename from .ci/eden.dwfsprof
rename to .ci/linux/eden.dwfsprof
diff --git a/.ci/package-appimage.sh b/.ci/linux/package.sh
similarity index 95%
rename from .ci/package-appimage.sh
rename to .ci/linux/package.sh
index 806d3bb802..2e5e3521e4 100755
--- a/.ci/package-appimage.sh
+++ b/.ci/linux/package.sh
@@ -1,5 +1,8 @@
 #!/bin/sh
 
+# SPDX-FileCopyrightText: 2025 eden Emulator Project
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 # This script assumes you're in the source directory
 set -ex
 
@@ -113,7 +116,7 @@ echo "Generating AppImage..."
 ./uruntime --appimage-mkdwarfs -f \
 	--set-owner 0 --set-group 0 \
 	--no-history --no-create-timestamp \
-	--categorize=hotness --hotness-list=.ci/eden.dwfsprof \
+	--categorize=hotness --hotness-list=.ci/linux/eden.dwfsprof \
 	--compression zstd:level=22 -S26 -B32 \
 	--header uruntime \
     -N 4 \
diff --git a/.ci/windows/build-bqt.bat b/.ci/windows/build-bqt.bat
new file mode 100755
index 0000000000..925d420690
--- /dev/null
+++ b/.ci/windows/build-bqt.bat
@@ -0,0 +1,27 @@
+echo off
+
+set chain=%1
+
+if not defined DevEnvDir (
+	"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" %chain%
+)
+
+mkdir build
+
+cmake -S . -B build\%chain% ^
+-DCMAKE_BUILD_TYPE=Release ^
+-DYUZU_USE_BUNDLED_QT=ON ^
+-DENABLE_QT_TRANSLATION=ON ^
+-DUSE_DISCORD_PRESENCE=ON ^
+-DYUZU_USE_BUNDLED_VCPKG=ON ^
+-DYUZU_USE_BUNDLED_SDL2=ON ^
+-G "Ninja" ^
+-DYUZU_TESTS=OFF ^
+-DCMAKE_C_COMPILER_LAUNCHER=ccache ^
+-DCMAKE_CXX_COMPILER_LAUNCHER=ccache ^
+-DCMAKE_TOOLCHAIN_FILE="%CD%\CMakeModules\MSVCCache.cmake" ^
+-DUSE_CCACHE=ON
+
+cmake --build build\%chain%
+
+ccache -s -v
\ No newline at end of file
diff --git a/.ci/windows/build.bat b/.ci/windows/build.bat
new file mode 100755
index 0000000000..4dbe862a94
--- /dev/null
+++ b/.ci/windows/build.bat
@@ -0,0 +1,31 @@
+echo off
+
+set chain=%1
+set qt_ver=%2
+
+if not defined DevEnvDir (
+	CALL "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" %chain%
+)
+
+CALL mkdir build
+
+CALL cmake -S . -B build\%chain% ^
+-DCMAKE_BUILD_TYPE=Release ^
+-DYUZU_USE_BUNDLED_QT=ON ^
+-DENABLE_QT_TRANSLATION=ON ^
+-DUSE_DISCORD_PRESENCE=ON ^
+-DYUZU_USE_BUNDLED_VCPKG=ON ^
+-DYUZU_USE_BUNDLED_SDL2=ON ^
+-G "Ninja" ^
+-DYUZU_TESTS=OFF ^
+-DUSE_BUNDLED_QT=OFF ^
+-DUSE_SYSTEM_QT=ON ^
+-DCMAKE_PREFIX_PATH=C:\Qt\%qt_ver%\msvc2022_64 ^
+-DCMAKE_C_COMPILER_LAUNCHER=ccache ^
+-DCMAKE_CXX_COMPILER_LAUNCHER=ccache ^
+-DCMAKE_TOOLCHAIN_FILE="%CD%\CMakeModules\MSVCCache.cmake" ^
+-DUSE_CCACHE=ON
+
+CALL cmake --build build\%chain%
+
+CALL ccache -s -v
\ No newline at end of file
diff --git a/.ci/windows/cygwin.bat b/.ci/windows/cygwin.bat
new file mode 100755
index 0000000000..e772780fac
--- /dev/null
+++ b/.ci/windows/cygwin.bat
@@ -0,0 +1,19 @@
+echo off
+
+call C:\tools\cygwin\cygwinsetup.exe -q -P autoconf,automake,libtool,make,pkg-config
+
+REM Create wrapper batch files for Cygwin tools in a directory that will be in PATH
+REM uncomment this for first-run only
+REM call mkdir C:\cygwin-wrappers
+
+REM Create autoconf.bat wrapper
+call echo @echo off > C:\cygwin-wrappers\autoconf.bat
+call echo C:\tools\cygwin\bin\bash.exe -l -c "autoconf %%*" >> C:\cygwin-wrappers\autoconf.bat
+
+REM Add other wrappers if needed for other Cygwin tools
+call echo @echo off > C:\cygwin-wrappers\automake.bat
+call echo C:\tools\cygwin\bin\bash.exe -l -c "automake %%*" >> C:\cygwin-wrappers\automake.bat
+
+REM Add the wrappers directory to PATH
+call echo C:\cygwin-wrappers>>"%GITHUB_PATH%"
+call echo C:\tools\cygwin\bin>>"%GITHUB_PATH%"
diff --git a/.ci/install-vulkan-sdk.ps1 b/.ci/windows/install-vulkan-sdk.ps1
old mode 100644
new mode 100755
similarity index 100%
rename from .ci/install-vulkan-sdk.ps1
rename to .ci/windows/install-vulkan-sdk.ps1
diff --git a/.ci/windows/package.ps1 b/.ci/windows/package.ps1
new file mode 100755
index 0000000000..de7fd051bb
--- /dev/null
+++ b/.ci/windows/package.ps1
@@ -0,0 +1,41 @@
+# SPDX-FileCopyrightText: 2025 eden Emulator Project
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+$target=$args[0]
+$debug=$args[1]
+
+$GITDATE = $(git show -s --date=short --format='%ad') -replace "-", ""
+$GITREV = $(git show -s --format='%h')
+$RELEASE_DIST = "eden-windows-msvc"
+$ARTIFACTS_DIR = "artifacts"
+
+New-Item -ItemType Directory -Path $ARTIFACTS_DIR -Force
+New-Item -ItemType Directory -Path $RELEASE_DIST -Force
+
+if ($debug -eq "yes") {
+	mkdir -p pdb
+	$BUILD_PDB = "eden-windows-msvc-$GITDATE-$GITREV-debugsymbols.zip"
+	Get-ChildItem "build/$target/bin/" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb -ErrorAction SilentlyContinue
+
+	if (Test-Path -Path ".\pdb\*.pdb") {
+		7z a -tzip $BUILD_PDB .\pdb\*.pdb
+		Move-Item $BUILD_PDB $ARTIFACTS_DIR/ -ErrorAction SilentlyContinue
+	}
+} else {
+	Get-ChildItem "build/$target/bin/" -Recurse -Filter "*.pdb" | Remove-Item -Force -ErrorAction SilentlyContinue
+}
+
+Copy-Item "build/$target/bin/Release/*" -Destination "$RELEASE_DIST" -Recurse -ErrorAction SilentlyContinue
+if (-not $?) {
+	# Try without Release subfolder if that doesn't exist
+	Copy-Item "build/$target/bin/*" -Destination "$RELEASE_DIST" -Recurse -ErrorAction SilentlyContinue
+}
+
+
+$BUILD_ZIP = "eden-windows-msvc-$GITDATE-$GITREV.zip"
+
+7z a -tzip $BUILD_ZIP $RELEASE_DIST\*
+
+Move-Item $BUILD_ZIP $ARTIFACTS_DIR/ -Force #-ErrorAction SilentlyContinue
+Copy-Item "LICENSE*" -Destination "$RELEASE_DIST" -ErrorAction SilentlyContinue
+Copy-Item "README*" -Destination "$RELEASE_DIST" -ErrorAction SilentlyContinue
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0b7756cd2a..520e9562e7 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,6 +8,7 @@ on:
   pull_request:
     branches: [ master ]
 
+# TODO: combine build.yml into trigger_release.yml
 jobs:
   source:
     if: ${{ !github.head_ref }}
@@ -23,6 +24,7 @@ jobs:
         with:
           name: source.zip
           path: artifacts/
+
   windows:
     runs-on: windows
     strategy:
@@ -42,6 +44,7 @@ jobs:
         with:
           submodules: recursive
           fetch-depth: 0
+          fetch-tags: true
 
       - name: Set up vcpkg cache
         uses: actions/cache@v4
@@ -60,86 +63,23 @@ jobs:
 
       - name: Cygwin with autoconf # NEEDED FOR LIBUSB
         shell: cmd
-        run: |
-          C:\tools\cygwin\cygwinsetup.exe -q -P autoconf,automake,libtool,make,pkg-config
+        run: ./.ci/windows/cygwin.bat
 
-          REM Create wrapper batch files for Cygwin tools in a directory that will be in PATH
-          REM mkdir C:\cygwin-wrappers
-
-          REM Create autoconf.bat wrapper
-          echo @echo off > C:\cygwin-wrappers\autoconf.bat
-          echo C:\tools\cygwin\bin\bash.exe -l -c "autoconf %%*" >> C:\cygwin-wrappers\autoconf.bat
-
-          REM Add other wrappers if needed for other Cygwin tools
-          echo @echo off > C:\cygwin-wrappers\automake.bat
-          echo C:\tools\cygwin\bin\bash.exe -l -c "automake %%*" >> C:\cygwin-wrappers\automake.bat
-
-          REM Add the wrappers directory to PATH
-          echo C:\cygwin-wrappers>>"%GITHUB_PATH%"
-          echo C:\tools\cygwin\bin>>"%GITHUB_PATH%"
-
-      - name: CMake Configure
+      - name: Configure & Build
         id: cmake
         shell: cmd
-        run: |
-          mkdir build
-          cd build
-          cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_TOOLCHAIN_FILE="%CD%\..\CMakeModules\MSVCCache.cmake" -DYUZU_USE_BUNDLED_QT=ON -DENABLE_QT_TRANSLATION=ON -DUSE_DISCORD_PRESENCE=ON -DYUZU_USE_BUNDLED_VCPKG=ON -DYUZU_USE_BUNDLED_SDL2=ON -DUSE_CCACHE=ON
-
-      - name: Build
-        id: build
-        shell: cmd
-        run: |
-          cd build
-          ninja yuzu yuzu-cmd yuzu-room tests
-          ccache -s -v
+        run: ./.ci/windows/build-bqt.bat amd64 yes
 
       - name: Package artifacts
-        if: steps.build.outcome == 'success'
         shell: powershell
-        run: |
-          $GITDATE = $(git show -s --date=short --format='%ad') -replace "-", ""
-          $GITREV = $(git show -s --format='%h')
-          $RELEASE_DIST = "eden-windows-msvc"
-          $ARTIFACTS_DIR = "${{ github.workspace }}/artifacts"
-
-          mkdir -p $ARTIFACTS_DIR
-          mkdir -p $RELEASE_DIST
-          mkdir -p pdb
-
-          Copy-Item "build/bin/Release/*" -Destination "$RELEASE_DIST" -Recurse -ErrorAction SilentlyContinue
-          if (-not $?) {
-            # Try without Release subfolder if that doesn't exist
-            Copy-Item "build/bin/*" -Destination "$RELEASE_DIST" -Recurse -ErrorAction SilentlyContinue
-          }
-
-          Get-ChildItem "build/bin/" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb -ErrorAction SilentlyContinue
-
-          $BUILD_ZIP = "eden-windows-msvc-$GITDATE-$GITREV.zip"
-          $BUILD_PDB = "eden-windows-msvc-$GITDATE-$GITREV-debugsymbols.zip"
-          $BUILD_7Z = "eden-windows-msvc-$GITDATE-$GITREV.7z"
-
-          7z a -tzip $BUILD_ZIP $RELEASE_DIST\*
-
-          if (Test-Path -Path ".\pdb\*.pdb") {
-            7z a -tzip $BUILD_PDB .\pdb\*.pdb
-            Move-Item $BUILD_PDB $ARTIFACTS_DIR/ -ErrorAction SilentlyContinue
-          }
-
-          7z a $BUILD_7Z $RELEASE_DIST
-
-          Move-Item $BUILD_ZIP $ARTIFACTS_DIR/ -ErrorAction SilentlyContinue
-          Move-Item $BUILD_7Z $ARTIFACTS_DIR/ -ErrorAction SilentlyContinue
-
-          Copy-Item "LICENSE*" -Destination "$RELEASE_DIST" -ErrorAction SilentlyContinue
-          Copy-Item "README*" -Destination "$RELEASE_DIST" -ErrorAction SilentlyContinue
+        run: ./.ci/windows/package.ps1 amd64 yes
 
       - name: Upload Windows artifacts
-        if: steps.build.outcome == 'success'
         uses: forgejo/upload-artifact@v4
         with:
           name: ${{ matrix.target }}.zip
           path: artifacts/*
+
   linux:
     runs-on: linux
     env:
@@ -152,16 +92,14 @@ jobs:
       - uses: actions/checkout@v4
         with:
           submodules: recursive
-          fetch-depth: 1
+          fetch-depth: 0
           fetch-tags: true
 
       - name: Build
-        run: |
-          ./.ci/linux.sh v3 8
+        run: ./.ci/linux/build.sh v3 8
 
       - name: Package AppImage
-        run: |
-          ./.ci/package-appimage.sh v3 &> /dev/null
+        run: ./.ci/linux/package.sh v3 &> /dev/null
 
       - name: Upload Linux artifacts
         uses: forgejo/upload-artifact@v4
@@ -184,6 +122,7 @@ jobs:
         with:
           submodules: recursive
           fetch-depth: 0
+          fetch-tags: true
 
       - name: Set tag name
         run: |
@@ -193,27 +132,10 @@ jobs:
           echo $GIT_TAG_NAME
 
       - name: Build
-        run: JAVA_HOME=$JAVA_HOME_21_X64 ./.ci/android.sh
+        run: JAVA_HOME=$JAVA_HOME_21_X64 ./.ci/android/build.sh
 
       - name: Package Android artifacts
-        run: |
-          GITDATE="$(git show -s --date=short --format='%ad' | sed 's/-//g')"
-          GITREV="$(git show -s --format='%h')"
-          ARTIFACTS_DIR="$PWD/artifacts"
-          mkdir -p "${ARTIFACTS_DIR}/"
-
-          REV_NAME="eden-android-${GITDATE}-${GITREV}"
-          BUILD_FLAVOR="mainline"
-          BUILD_TYPE_LOWER="release"
-          BUILD_TYPE_UPPER="Release"
-
-          cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \
-             "${ARTIFACTS_DIR}/${REV_NAME}.apk" || echo "APK not found"
-
-          cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \
-             "${ARTIFACTS_DIR}/${REV_NAME}.aab" || echo "AAB not found"
-
-          ls -la "${ARTIFACTS_DIR}/"
+        run: ./.ci/android/package.sh
 
       - name: Upload Android artifacts
         uses: forgejo/upload-artifact@v4
diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml
index a248e14618..f388fcf6c6 100644
--- a/.github/workflows/trigger_release.yml
+++ b/.github/workflows/trigger_release.yml
@@ -41,6 +41,7 @@ jobs:
         with:
           submodules: recursive
           fetch-depth: 0
+          fetch-tags: true
 
       - name: Set up vcpkg cache
         uses: actions/cache@v4
@@ -59,67 +60,18 @@ jobs:
 
       - name: Cygwin with autoconf # NEEDED FOR LIBUSB
         shell: cmd
-        run: |
-          C:\tools\cygwin\cygwinsetup.exe -q -P autoconf,automake,libtool,make,pkg-config
+        run: ./.ci/windows/cygwin.bat
 
-          REM Create wrapper batch files for Cygwin tools in a directory that will be in PATH
-          REM mkdir C:\cygwin-wrappers
-
-          REM Create autoconf.bat wrapper
-          echo @echo off > C:\cygwin-wrappers\autoconf.bat
-          echo C:\tools\cygwin\bin\bash.exe -l -c "autoconf %%*" >> C:\cygwin-wrappers\autoconf.bat
-
-          REM Add other wrappers if needed for other Cygwin tools
-          echo @echo off > C:\cygwin-wrappers\automake.bat
-          echo C:\tools\cygwin\bin\bash.exe -l -c "automake %%*" >> C:\cygwin-wrappers\automake.bat
-
-          REM Add the wrappers directory to PATH
-          echo C:\cygwin-wrappers>>"%GITHUB_PATH%"
-          echo C:\tools\cygwin\bin>>"%GITHUB_PATH%"
-
-      - name: CMake Configure
+      - name: Configure & Build
         id: cmake
         shell: cmd
-        run: |
-          mkdir build
-          cd build
-          cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_TOOLCHAIN_FILE="%CD%\..\CMakeModules\MSVCCache.cmake" -DYUZU_USE_BUNDLED_QT=ON -DENABLE_QT_TRANSLATION=ON -DUSE_DISCORD_PRESENCE=ON -DYUZU_USE_BUNDLED_VCPKG=ON -DYUZU_USE_BUNDLED_SDL2=ON -DUSE_CCACHE=ON
-
-      - name: Build
-        id: build
-        shell: cmd
-        run: |
-          cd build
-          ninja yuzu yuzu-cmd yuzu-room tests
-          ccache -s -v
+        run: ./.ci/windows/build-bqt.bat amd64 no
 
       - name: Package artifacts
-        if: steps.build.outcome == 'success'
         shell: powershell
-        run: |
-          $GITDATE = $(git show -s --date=short --format='%ad') -replace "-", ""
-          $GITREV = $(git show -s --format='%h')
-          $RELEASE_DIST = "eden-windows-msvc"
-          $ARTIFACTS_DIR = "${{ github.workspace }}/artifacts"
-
-          mkdir -p $ARTIFACTS_DIR
-          mkdir -p $RELEASE_DIST
-
-          Copy-Item "build/bin/Release/*" -Destination "$RELEASE_DIST" -Recurse -ErrorAction SilentlyContinue
-          if (-not $?) {
-            # Try without Release subfolder if that doesn't exist
-            Copy-Item "build/bin/*" -Destination "$RELEASE_DIST" -Recurse -ErrorAction SilentlyContinue
-          }
-
-          $BUILD_ZIP = "eden-windows-msvc-$GITDATE-$GITREV.zip"
-          7z a -tzip $BUILD_ZIP $RELEASE_DIST\*
-          
-          Move-Item $BUILD_ZIP $ARTIFACTS_DIR/ -ErrorAction SilentlyContinue
-          Copy-Item "LICENSE*" -Destination "$RELEASE_DIST" -ErrorAction SilentlyContinue
-          Copy-Item "README*" -Destination "$RELEASE_DIST" -ErrorAction SilentlyContinue
+        run: ./.ci/windows/package.ps1 amd64 no
 
       - name: Upload Windows artifacts
-        if: steps.build.outcome == 'success'
         uses: forgejo/upload-artifact@v4
         with:
           name: ${{ matrix.target }}.zip
@@ -137,16 +89,14 @@ jobs:
       - uses: actions/checkout@v4
         with:
           submodules: recursive
-          fetch-depth: 1
+          fetch-depth: 0
           fetch-tags: true
 
       - name: Build
-        run: |
-          ./.ci/linux.sh v3 8
+        run: ./.ci/linux/build.sh v3 8
 
       - name: Package AppImage
-        run: |
-          ./.ci/package-appimage.sh v3 &> /dev/null
+        run: ./.ci/linux/package.sh v3 &> /dev/null
 
       - name: Upload Linux artifacts
         uses: forgejo/upload-artifact@v4
@@ -169,6 +119,7 @@ jobs:
         with:
           submodules: recursive
           fetch-depth: 0
+          fetch-tags: true
 
       - name: Set tag name
         run: |
@@ -178,27 +129,10 @@ jobs:
           echo $GIT_TAG_NAME
 
       - name: Build
-        run: JAVA_HOME=$JAVA_HOME_21_X64 ./.ci/android.sh
+        run: JAVA_HOME=$JAVA_HOME_21_X64 ./.ci/android/build.sh
 
       - name: Package Android artifacts
-        run: |
-          GITDATE="$(git show -s --date=short --format='%ad' | sed 's/-//g')"
-          GITREV="$(git show -s --format='%h')"
-          ARTIFACTS_DIR="$PWD/artifacts"
-          mkdir -p "${ARTIFACTS_DIR}/"
-
-          REV_NAME="eden-android-${GITDATE}-${GITREV}"
-          BUILD_FLAVOR="mainline"
-          BUILD_TYPE_LOWER="release"
-          BUILD_TYPE_UPPER="Release"
-
-          cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \
-             "${ARTIFACTS_DIR}/${REV_NAME}.apk" || echo "APK not found"
-
-          cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \
-             "${ARTIFACTS_DIR}/${REV_NAME}.aab" || echo "AAB not found"
-
-          ls -la "${ARTIFACTS_DIR}/"
+        run: ./.ci/android/package.sh
 
       - name: Upload Android artifacts
         uses: forgejo/upload-artifact@v4
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0e2705cf72..117a0e1265 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -62,7 +62,7 @@ if (MSVC)
 
         # Warnings
         /W4
-        /WX
+        /WX-
 
         /we4062 # Enumerator 'identifier' in a switch of enum 'enumeration' is not handled
         /we4189 # 'identifier': local variable is initialized but not referenced
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 5d852fe92b..6dac1ef84e 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -664,7 +664,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardInput(JNIEnv* env
 
 void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv* env,
                                                                         jobject instance) {
-    const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
+    const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
     auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory(
         Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
 
@@ -836,7 +836,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
     const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
     ASSERT(user_id);
 
-    const auto nandDir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
+    const auto nandDir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
     auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir),
                                                             FileSys::OpenMode::Read);
 
diff --git a/src/android/app/src/main/jni/native_input.cpp b/src/android/app/src/main/jni/native_input.cpp
index 4935a46070..5b69826c75 100644
--- a/src/android/app/src/main/jni/native_input.cpp
+++ b/src/android/app/src/main/jni/native_input.cpp
@@ -44,7 +44,7 @@ bool IsProfileNameValid(std::string_view profile_name) {
 }
 
 bool ProfileExistsInFilesystem(std::string_view profile_name) {
-    return Common::FS::Exists(Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "input" /
+    return Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "input" /
                               fmt::format("{}.ini", profile_name));
 }
 
@@ -304,7 +304,7 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_loadInputProfiles(JNIEnv
                                                                           jobject j_obj) {
     map_profiles.clear();
     const auto input_profile_loc =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "input";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "input";
 
     if (Common::FS::IsDir(input_profile_loc)) {
         Common::FS::IterateDirEntries(
diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h
index 5b9579ac29..c1e05577ff 100644
--- a/src/common/fs/fs_paths.h
+++ b/src/common/fs/fs_paths.h
@@ -1,11 +1,14 @@
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 #pragma once
 
 // yuzu data directories
 
-#define YUZU_DIR "yuzu"
+#define EDEN_DIR "eden"
 #define PORTABLE_DIR "user"
 
 // Sub-directories contained within a yuzu data directory
@@ -25,6 +28,10 @@
 #define SHADER_DIR "shader"
 #define TAS_DIR "tas"
 #define ICONS_DIR "icons"
+#define CITRON_DIR "citron"
+#define SUDACHI_DIR "sudachi"
+#define YUZU_DIR "yuzu"
+#define SUYU_DIR "suyu"
 
 // yuzu-specific files
 
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index 4f69db6f5c..296ef69b30 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -1,7 +1,11 @@
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 #include <algorithm>
+#include <iostream>
 #include <sstream>
 #include <unordered_map>
 
@@ -56,10 +60,10 @@ namespace fs = std::filesystem;
 
 /**
  * The PathManagerImpl is a singleton allowing to manage the mapping of
- * YuzuPath enums to real filesystem paths.
- * This class provides 2 functions: GetYuzuPathImpl and SetYuzuPathImpl.
- * These are used by GetYuzuPath and SetYuzuPath respectively to get or modify
- * the path mapped by the YuzuPath enum.
+ * EdenPath enums to real filesystem paths.
+ * This class provides 2 functions: GetEdenPathImpl and SetEdenPathImpl.
+ * These are used by GetEdenPath and SetEdenPath respectively to get or modify
+ * the path mapped by the EdenPath enum.
  */
 class PathManagerImpl {
 public:
@@ -75,62 +79,99 @@ public:
     PathManagerImpl(PathManagerImpl&&) = delete;
     PathManagerImpl& operator=(PathManagerImpl&&) = delete;
 
-    [[nodiscard]] const fs::path& GetYuzuPathImpl(YuzuPath yuzu_path) {
-        return yuzu_paths.at(yuzu_path);
+    [[nodiscard]] const fs::path& GetEdenPathImpl(EdenPath eden_path) {
+        return eden_paths.at(eden_path);
     }
 
-    void SetYuzuPathImpl(YuzuPath yuzu_path, const fs::path& new_path) {
-        yuzu_paths.insert_or_assign(yuzu_path, new_path);
+    [[nodiscard]] const fs::path& GetLegacyPathImpl(LegacyPath legacy_path) {
+        return legacy_paths.at(legacy_path);
     }
 
-    void Reinitialize(fs::path yuzu_path = {}) {
-        fs::path yuzu_path_cache;
-        fs::path yuzu_path_config;
+    void CreateEdenPaths() {
+        std::for_each(eden_paths.begin(), eden_paths.end(), [](auto &path) {
+            void(FS::CreateDir(path.second));
+        });
+    }
+
+    void SetEdenPathImpl(EdenPath eden_path, const fs::path& new_path) {
+        eden_paths.insert_or_assign(eden_path, new_path);
+    }
+
+    void SetLegacyPathImpl(LegacyPath legacy_path, const fs::path& new_path) {
+        legacy_paths.insert_or_assign(legacy_path, new_path);
+    }
+
+    void Reinitialize(fs::path eden_path = {}) {
+        fs::path eden_path_cache;
+        fs::path eden_path_config;
 
 #ifdef _WIN32
 #ifdef YUZU_ENABLE_PORTABLE
-        yuzu_path = GetExeDirectory() / PORTABLE_DIR;
+        eden_path = GetExeDirectory() / PORTABLE_DIR;
 #endif
-        if (!IsDir(yuzu_path)) {
-            yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR;
+        if (!IsDir(eden_path)) {
+            eden_path = GetAppDataRoamingDirectory() / EDEN_DIR;
         }
 
-        yuzu_path_cache = yuzu_path / CACHE_DIR;
-        yuzu_path_config = yuzu_path / CONFIG_DIR;
+        eden_path_cache = eden_path / CACHE_DIR;
+        eden_path_config = eden_path / CONFIG_DIR;
+
+#define LEGACY_PATH(titleName, upperName) GenerateLegacyPath(LegacyPath::titleName##Dir, GetAppDataRoamingDirectory() / upperName##_DIR); \
+        GenerateLegacyPath(LegacyPath::titleName##ConfigDir, GetAppDataRoamingDirectory() / upperName##_DIR / CONFIG_DIR); \
+        GenerateLegacyPath(LegacyPath::titleName##CacheDir, GetAppDataRoamingDirectory() / upperName##_DIR / CACHE_DIR);
+
+        LEGACY_PATH(Citron, CITRON)
+        LEGACY_PATH(Sudachi, SUDACHI)
+        LEGACY_PATH(Yuzu, YUZU)
+        LEGACY_PATH(Suyu, SUYU)
+#undef LEGACY_PATH
+
 #elif ANDROID
-        ASSERT(!yuzu_path.empty());
-        yuzu_path_cache = yuzu_path / CACHE_DIR;
-        yuzu_path_config = yuzu_path / CONFIG_DIR;
+        ASSERT(!eden_path.empty());
+        eden_path_cache = eden_path / CACHE_DIR;
+        eden_path_config = eden_path / CONFIG_DIR;
 #else
 #ifdef YUZU_ENABLE_PORTABLE
-        yuzu_path = GetCurrentDir() / PORTABLE_DIR;
+        eden_path = GetCurrentDir() / PORTABLE_DIR;
 #endif
-        if (Exists(yuzu_path) && IsDir(yuzu_path)) {
-            yuzu_path_cache = yuzu_path / CACHE_DIR;
-            yuzu_path_config = yuzu_path / CONFIG_DIR;
+        if (Exists(eden_path) && IsDir(eden_path)) {
+            eden_path_cache = eden_path / CACHE_DIR;
+            eden_path_config = eden_path / CONFIG_DIR;
         } else {
-            yuzu_path = GetDataDirectory("XDG_DATA_HOME") / YUZU_DIR;
-            yuzu_path_cache = GetDataDirectory("XDG_CACHE_HOME") / YUZU_DIR;
-            yuzu_path_config = GetDataDirectory("XDG_CONFIG_HOME") / YUZU_DIR;
+            eden_path = GetDataDirectory("XDG_DATA_HOME") / EDEN_DIR;
+            eden_path_cache = GetDataDirectory("XDG_CACHE_HOME") / EDEN_DIR;
+            eden_path_config = GetDataDirectory("XDG_CONFIG_HOME") / EDEN_DIR;
         }
+
+#define LEGACY_PATH(titleName, upperName) GenerateLegacyPath(LegacyPath::titleName##Dir, GetDataDirectory("XDG_DATA_HOME") / upperName##_DIR); \
+        GenerateLegacyPath(LegacyPath::titleName##ConfigDir, GetDataDirectory("XDG_CONFIG_HOME") / upperName##_DIR); \
+        GenerateLegacyPath(LegacyPath::titleName##CacheDir, GetDataDirectory("XDG_CACHE_HOME") / upperName##_DIR);
+
+        LEGACY_PATH(Citron, CITRON)
+        LEGACY_PATH(Sudachi, SUDACHI)
+        LEGACY_PATH(Yuzu, YUZU)
+        LEGACY_PATH(Suyu, SUYU)
+
+#undef LEGACY_PATH
+
 #endif
 
-        GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
-        GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR);
-        GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache);
-        GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config);
-        GenerateYuzuPath(YuzuPath::CrashDumpsDir, yuzu_path / CRASH_DUMPS_DIR);
-        GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
-        GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR);
-        GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
-        GenerateYuzuPath(YuzuPath::LogDir, yuzu_path / LOG_DIR);
-        GenerateYuzuPath(YuzuPath::NANDDir, yuzu_path / NAND_DIR);
-        GenerateYuzuPath(YuzuPath::PlayTimeDir, yuzu_path / PLAY_TIME_DIR);
-        GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR);
-        GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR);
-        GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR);
-        GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR);
-        GenerateYuzuPath(YuzuPath::IconsDir, yuzu_path / ICONS_DIR);
+        GenerateEdenPath(EdenPath::EdenDir, eden_path);
+        GenerateEdenPath(EdenPath::AmiiboDir, eden_path / AMIIBO_DIR);
+        GenerateEdenPath(EdenPath::CacheDir, eden_path_cache);
+        GenerateEdenPath(EdenPath::ConfigDir, eden_path_config);
+        GenerateEdenPath(EdenPath::CrashDumpsDir, eden_path / CRASH_DUMPS_DIR);
+        GenerateEdenPath(EdenPath::DumpDir, eden_path / DUMP_DIR);
+        GenerateEdenPath(EdenPath::KeysDir, eden_path / KEYS_DIR);
+        GenerateEdenPath(EdenPath::LoadDir, eden_path / LOAD_DIR);
+        GenerateEdenPath(EdenPath::LogDir, eden_path / LOG_DIR);
+        GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR);
+        GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR);
+        GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
+        GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
+        GenerateEdenPath(EdenPath::ShaderDir, eden_path / SHADER_DIR);
+        GenerateEdenPath(EdenPath::TASDir, eden_path / TAS_DIR);
+        GenerateEdenPath(EdenPath::IconsDir, eden_path / ICONS_DIR);
     }
 
 private:
@@ -140,13 +181,17 @@ private:
 
     ~PathManagerImpl() = default;
 
-    void GenerateYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
-        void(FS::CreateDir(new_path));
-
-        SetYuzuPathImpl(yuzu_path, new_path);
+    void GenerateEdenPath(EdenPath eden_path, const fs::path& new_path) {
+        // Defer path creation
+        SetEdenPathImpl(eden_path, new_path);
     }
 
-    std::unordered_map<YuzuPath, fs::path> yuzu_paths;
+    void GenerateLegacyPath(LegacyPath legacy_path, const fs::path& new_path) {
+        SetLegacyPathImpl(legacy_path, new_path);
+    }
+
+    std::unordered_map<EdenPath, fs::path> eden_paths;
+    std::unordered_map<LegacyPath, fs::path> legacy_paths;
 };
 
 bool ValidatePath(const fs::path& path) {
@@ -230,22 +275,35 @@ void SetAppDirectory(const std::string& app_directory) {
     PathManagerImpl::GetInstance().Reinitialize(app_directory);
 }
 
-const fs::path& GetYuzuPath(YuzuPath yuzu_path) {
-    return PathManagerImpl::GetInstance().GetYuzuPathImpl(yuzu_path);
+const fs::path& GetEdenPath(EdenPath eden_path) {
+    return PathManagerImpl::GetInstance().GetEdenPathImpl(eden_path);
 }
 
-std::string GetYuzuPathString(YuzuPath yuzu_path) {
-    return PathToUTF8String(GetYuzuPath(yuzu_path));
+const std::filesystem::path& GetLegacyPath(LegacyPath legacy_path) {
+    return PathManagerImpl::GetInstance().GetLegacyPathImpl(legacy_path);
 }
 
-void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
+std::string GetEdenPathString(EdenPath eden_path) {
+    return PathToUTF8String(GetEdenPath(eden_path));
+}
+
+std::string GetLegacyPathString(LegacyPath legacy_path) {
+    return PathToUTF8String(GetLegacyPath(legacy_path));
+}
+
+void SetEdenPath(EdenPath eden_path, const fs::path& new_path) {
     if (!FS::IsDir(new_path)) {
         LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} is not a directory",
                   PathToUTF8String(new_path));
         return;
     }
 
-    PathManagerImpl::GetInstance().SetYuzuPathImpl(yuzu_path, new_path);
+    PathManagerImpl::GetInstance().SetEdenPathImpl(eden_path, new_path);
+}
+
+void CreateEdenPaths()
+{
+    PathManagerImpl::GetInstance().CreateEdenPaths();
 }
 
 #ifdef _WIN32
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 59301e7edd..1dd95391f7 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -1,6 +1,9 @@
 // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 #pragma once
 
 #include <filesystem>
@@ -10,8 +13,8 @@
 
 namespace Common::FS {
 
-enum class YuzuPath {
-    YuzuDir,        // Where yuzu stores its data.
+enum class EdenPath {
+    EdenDir,        // Where yuzu stores its data.
     AmiiboDir,      // Where Amiibo backups are stored.
     CacheDir,       // Where cached filesystem data is stored.
     ConfigDir,      // Where config files are stored.
@@ -29,6 +32,24 @@ enum class YuzuPath {
     IconsDir,       // Where Icons for Windows shortcuts are stored.
 };
 
+enum LegacyPath {
+    CitronDir, // Citron Directories for migration
+    CitronConfigDir,
+    CitronCacheDir,
+
+    SudachiDir, // Sudachi Directories for migration
+    SudachiConfigDir,
+    SudachiCacheDir,
+
+    YuzuDir, // Yuzu Directories for migration
+    YuzuConfigDir,
+    YuzuCacheDir,
+
+    SuyuDir, // Suyu Directories for migration
+    SuyuConfigDir,
+    SuyuCacheDir,
+};
+
 /**
  * Validates a given path.
  *
@@ -193,39 +214,62 @@ template <typename Path>
 void SetAppDirectory(const std::string& app_directory);
 
 /**
- * Gets the filesystem path associated with the YuzuPath enum.
+ * Gets the filesystem path associated with the EdenPath enum.
  *
- * @param yuzu_path YuzuPath enum
+ * @param eden_path EdenPath enum
  *
- * @returns The filesystem path associated with the YuzuPath enum.
+ * @returns The filesystem path associated with the EdenPath enum.
  */
-[[nodiscard]] const std::filesystem::path& GetYuzuPath(YuzuPath yuzu_path);
+[[nodiscard]] const std::filesystem::path& GetEdenPath(EdenPath eden_path);
 
 /**
- * Gets the filesystem path associated with the YuzuPath enum as a UTF-8 encoded std::string.
+ * Gets the filesystem path associated with the LegacyPath enum.
  *
- * @param yuzu_path YuzuPath enum
+ * @param legacy_path LegacyPath enum
  *
- * @returns The filesystem path associated with the YuzuPath enum as a UTF-8 encoded std::string.
+ * @returns The filesystem path associated with the LegacyPath enum.
  */
-[[nodiscard]] std::string GetYuzuPathString(YuzuPath yuzu_path);
+[[nodiscard]] const std::filesystem::path& GetLegacyPath(LegacyPath legacy_path);
 
 /**
- * Sets a new filesystem path associated with the YuzuPath enum.
+ * Gets the filesystem path associated with the EdenPath enum as a UTF-8 encoded std::string.
+ *
+ * @param eden_path EdenPath enum
+ *
+ * @returns The filesystem path associated with the EdenPath enum as a UTF-8 encoded std::string.
+ */
+[[nodiscard]] std::string GetEdenPathString(EdenPath eden_path);
+
+/**
+ * Gets the filesystem path associated with the LegacyPath enum as a UTF-8 encoded std::string.
+ *
+ * @param legacy_path LegacyPath enum
+ *
+ * @returns The filesystem path associated with the LegacyPath enum as a UTF-8 encoded std::string.
+ */
+[[nodiscard]] std::string GetLegacyPathString(LegacyPath legacy_path);
+
+/**
+ * Sets a new filesystem path associated with the EdenPath enum.
  * If the filesystem object at new_path is not a directory, this function will not do anything.
  *
- * @param yuzu_path YuzuPath enum
+ * @param eden_path EdenPath enum
  * @param new_path New filesystem path
  */
-void SetYuzuPath(YuzuPath yuzu_path, const std::filesystem::path& new_path);
+void SetEdenPath(EdenPath eden_path, const std::filesystem::path& new_path);
+
+/**
+ * Creates all necessary Eden paths in the filesystem.
+ */
+void CreateEdenPaths();
 
 #ifdef _WIN32
 template <typename Path>
-void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
+void SetEdenPath(EdenPath eden_path, const Path& new_path) {
     if constexpr (IsChar<typename Path::value_type>) {
-        SetYuzuPath(yuzu_path, ToU8String(new_path));
+        SetEdenPath(eden_path, ToU8String(new_path));
     } else {
-        SetYuzuPath(yuzu_path, std::filesystem::path{new_path});
+        SetEdenPath(eden_path, std::filesystem::path{new_path});
     }
 }
 #endif
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 3b400c6566..e5bf6b723a 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -200,7 +200,7 @@ public:
             return;
         }
         using namespace Common::FS;
-        const auto& log_dir = GetYuzuPath(YuzuPath::LogDir);
+        const auto& log_dir = GetEdenPath(EdenPath::LogDir);
         void(CreateDir(log_dir));
         Filter filter;
         filter.ParseFilterString(Settings::values.log_filter.GetValue());
diff --git a/src/common/nvidia_flags.cpp b/src/common/nvidia_flags.cpp
index 5e44c0c6ca..baca31b0ac 100644
--- a/src/common/nvidia_flags.cpp
+++ b/src/common/nvidia_flags.cpp
@@ -14,7 +14,7 @@ namespace Common {
 void ConfigureNvidiaEnvironmentFlags() {
 #ifdef _WIN32
     const auto nvidia_shader_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir) / "nvidia";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir) / "nvidia";
 
     if (!Common::FS::CreateDirs(nvidia_shader_dir)) {
         return;
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index ee7074b128..cb6431d536 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -131,11 +131,11 @@ void LogSettings() {
             log_setting(name, setting->Canonicalize());
         }
     }
-    log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
-    log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
-    log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
-    log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
-    log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
+    log_path("DataStorage_CacheDir", Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir));
+    log_path("DataStorage_ConfigDir", Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir));
+    log_path("DataStorage_LoadDir", Common::FS::GetEdenPath(Common::FS::EdenPath::LoadDir));
+    log_path("DataStorage_NANDDir", Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir));
+    log_path("DataStorage_SDMCDir", Common::FS::GetEdenPath(Common::FS::EdenPath::SDMCDir));
 }
 
 void UpdateGPUAccuracy() {
diff --git a/src/common/settings.h b/src/common/settings.h
index 709ca03e7c..47dc65afa8 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -629,6 +629,7 @@ struct Values {
     Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
     Setting<bool> log_flush_lines{linkage, false, "flush_lines", Category::Miscellaneous};
     Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
+    Setting<bool> first_launch{linkage, true, "first_launch", Category::Miscellaneous};
 
     // Network
     Setting<std::string> network_interface{linkage, std::string(), "network_interface",
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 43a3c5ffd6..74b1ca04b1 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -372,7 +372,7 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source)
 
 std::optional<Key128> DeriveSDSeed() {
     const auto system_save_43_path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000043";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000043";
     const Common::FS::IOFile save_43{system_save_43_path, Common::FS::FileAccessMode::Read,
                                      Common::FS::FileType::BinaryFile};
 
@@ -381,7 +381,7 @@ std::optional<Key128> DeriveSDSeed() {
     }
 
     const auto sd_private_path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "Nintendo/Contents/private";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::SDMCDir) / "Nintendo/Contents/private";
 
     const Common::FS::IOFile sd_private{sd_private_path, Common::FS::FileAccessMode::Read,
                                         Common::FS::FileType::BinaryFile};
@@ -640,7 +640,7 @@ KeyManager::KeyManager() {
 
 void KeyManager::ReloadKeys() {
     // Initialize keys
-    const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+    const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
 
     if (!Common::FS::CreateDir(yuzu_keys_dir)) {
         LOG_ERROR(Core, "Failed to create the keys directory.");
@@ -847,7 +847,7 @@ Key256 KeyManager::GetBISKey(u8 partition_id) const {
 template <size_t Size>
 void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
                                 const std::array<u8, Size>& key) {
-    const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+    const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
 
     std::string filename = "title.keys_autogenerated";
 
@@ -947,7 +947,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
 }
 
 bool KeyManager::KeyFileExists(bool title) {
-    const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+    const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
 
     if (title) {
         return Common::FS::Exists(yuzu_keys_dir / "title.keys");
@@ -1197,7 +1197,7 @@ void KeyManager::PopulateTickets() {
     std::vector<Ticket> tickets;
 
     const auto system_save_e1_path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/80000000000000e1";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/80000000000000e1";
     if (Common::FS::Exists(system_save_e1_path)) {
         const Common::FS::IOFile save_e1{system_save_e1_path, Common::FS::FileAccessMode::Read,
                                          Common::FS::FileType::BinaryFile};
@@ -1206,7 +1206,7 @@ void KeyManager::PopulateTickets() {
     }
 
     const auto system_save_e2_path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/80000000000000e2";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/80000000000000e2";
     if (Common::FS::Exists(system_save_e2_path)) {
         const Common::FS::IOFile save_e2{system_save_e2_path, Common::FS::FileAccessMode::Read,
                                          Common::FS::FileType::BinaryFile};
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 6326b70492..6facd03f6d 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -83,7 +83,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
                                              VirtualFilesystem file_system) const {
     auto& keys = Core::Crypto::KeyManager::Instance();
     Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
-        Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), OpenMode::Read)};
+        Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir), OpenMode::Read)};
     keys.PopulateFromPartitionData(pdm);
 
     switch (id) {
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 15649e7ccf..7e4001ef92 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -36,7 +36,7 @@ namespace Service::Account {
 constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
 
 static std::filesystem::path GetImagePath(const Common::UUID& uuid) {
-    return Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
+    return Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) /
            fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString());
 }
 
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 39fed63f9d..55f544184b 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -377,7 +377,7 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase&
 }
 
 void ProfileManager::ParseUserSaveFile() {
-    const auto save_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH /
+    const auto save_path(FS::GetEdenPath(FS::EdenPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH /
                          "profiles.dat");
     const FS::IOFile save(save_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile);
 
@@ -429,12 +429,12 @@ void ProfileManager::WriteUserSaveFile() {
         };
     }
 
-    const auto raw_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / "system/save/8000000000000010");
+    const auto raw_path(FS::GetEdenPath(FS::EdenPath::NANDDir) / "system/save/8000000000000010");
     if (FS::IsFile(raw_path) && !FS::RemoveFile(raw_path)) {
         return;
     }
 
-    const auto save_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH /
+    const auto save_path(FS::GetEdenPath(FS::EdenPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH /
                          "profiles.dat");
 
     if (!FS::CreateParentDirs(save_path)) {
diff --git a/src/core/hle/service/am/frontend/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp
index 835c20c4e2..e35a1daa1e 100644
--- a/src/core/hle/service/am/frontend/applet_web_browser.cpp
+++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp
@@ -155,7 +155,7 @@ void ExtractSharedFonts(Core::System& system) {
         "FontNintendoExtended2.ttf",
     };
 
-    const auto fonts_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts";
+    const auto fonts_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "fonts";
 
     for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) {
         const auto font_file_path = fonts_dir / DECRYPTED_SHARED_FONTS[i];
@@ -415,7 +415,7 @@ void WebBrowser::InitializeOffline() {
         "system_data",
     };
 
-    offline_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
+    offline_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) /
                         fmt::format("offline_web_applet_{}/{:016X}",
                                     RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id);
 
diff --git a/src/core/hle/service/am/process_creation.cpp b/src/core/hle/service/am/process_creation.cpp
index 81a8fb0b44..b5e31353a2 100644
--- a/src/core/hle/service/am/process_creation.cpp
+++ b/src/core/hle/service/am/process_creation.cpp
@@ -106,7 +106,7 @@ std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
         out_control = nacp.GetRawBytes();
     } else {
         out_control.resize(sizeof(FileSys::RawNACP));
-        std::fill(out_control.begin(), out_control.end(), 0);
+        std::fill(out_control.begin(), out_control.end(), (u8) 0);
     }
 
     auto& storage = system.GetContentProviderUnion();
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
index 7f0bc127f9..e636d90bc4 100644
--- a/src/core/hle/service/caps/caps_manager.cpp
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -303,7 +303,7 @@ void AlbumManager::FindScreenshots() {
     album_files.clear();
 
     // TODO: Swap this with a blocking operation.
-    const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir);
+    const auto screenshots_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ScreenshotsDir);
     Common::FS::IterateDirEntries(
         screenshots_dir,
         [this](const std::filesystem::path& full_path) {
@@ -438,7 +438,7 @@ static void PNGToMemory(void* context, void* data, int len) {
 Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
                                u64 title_id, const AlbumFileDateTime& date) const {
     const auto screenshot_path =
-        Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir);
+        Common::FS::GetEdenPathString(Common::FS::EdenPath::ScreenshotsDir);
     const std::string formatted_date =
         fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day,
                     date.hour, date.minute, date.second, 0);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index ae230afc0e..9d7de4242e 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -346,12 +346,12 @@ std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController
 
 std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory(
     ProgramId program_id) {
-    using YuzuPath = Common::FS::YuzuPath;
+    using EdenPath = Common::FS::EdenPath;
     const auto rw_mode = FileSys::OpenMode::ReadWrite;
 
     auto vfs = system.GetFilesystem();
     const auto nand_directory =
-        vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
+        vfs->OpenDirectory(Common::FS::GetEdenPathString(EdenPath::NANDDir), rw_mode);
     return std::make_shared<FileSys::SaveDataFactory>(system, program_id,
                                                       std::move(nand_directory));
 }
@@ -683,20 +683,20 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
         sdmc_factory = nullptr;
     }
 
-    using YuzuPath = Common::FS::YuzuPath;
-    const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir);
+    using EdenPath = Common::FS::EdenPath;
+    const auto sdmc_dir_path = Common::FS::GetEdenPath(EdenPath::SDMCDir);
     const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents";
     const auto rw_mode = FileSys::OpenMode::ReadWrite;
 
     auto nand_directory =
-        vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
+        vfs.OpenDirectory(Common::FS::GetEdenPathString(EdenPath::NANDDir), rw_mode);
     auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode);
-    auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir),
+    auto load_directory = vfs.OpenDirectory(Common::FS::GetEdenPathString(EdenPath::LoadDir),
                                             FileSys::OpenMode::Read);
     auto sd_load_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path),
                                                FileSys::OpenMode::Read);
     auto dump_directory =
-        vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode);
+        vfs.OpenDirectory(Common::FS::GetEdenPathString(EdenPath::DumpDir), rw_mode);
 
     if (bis_factory == nullptr) {
         bis_factory = std::make_unique<FileSys::BISFactory>(
diff --git a/src/core/hle/service/mii/mii_database_manager.cpp b/src/core/hle/service/mii/mii_database_manager.cpp
index 0080b67051..a0291d4b55 100644
--- a/src/core/hle/service/mii/mii_database_manager.cpp
+++ b/src/core/hle/service/mii/mii_database_manager.cpp
@@ -22,9 +22,9 @@ DatabaseManager::DatabaseManager() {}
 Result DatabaseManager::MountSaveData() {
     if (!is_save_data_mounted) {
         system_save_dir =
-            Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000030";
+            Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000030";
         if (is_test_db) {
-            system_save_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
+            system_save_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) /
                               "system/save/8000000000000031";
         }
 
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index 4274a92c9e..158fa8ed51 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -271,7 +271,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
 }
 
 bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) {
-    const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+    const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
 
     const Common::FS::IOFile keys_file{yuzu_keys_dir / "key_retail.bin",
                                        Common::FS::FileAccessMode::Read,
@@ -295,7 +295,7 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) {
 }
 
 bool IsKeyAvailable() {
-    const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+    const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
     return Common::FS::Exists(yuzu_keys_dir / "key_retail.bin");
 }
 
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 96c45b1b51..30eab469a1 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -1261,7 +1261,7 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
 Result NfcDevice::HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const {
     ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
     constexpr auto backup_dir = "backup";
-    const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+    const auto yuzu_amiibo_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::AmiiboDir);
     const auto file_name =
         fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
 
@@ -1282,7 +1282,7 @@ Result NfcDevice::ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid
                                  std::span<u8> data) const {
     ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
     constexpr auto backup_dir = "backup";
-    const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+    const auto yuzu_amiibo_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::AmiiboDir);
     const auto file_name =
         fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
 
@@ -1313,7 +1313,7 @@ Result NfcDevice::WriteBackupData(const UniqueSerialNumber& uid, std::size_t uui
                                   std::span<const u8> data) {
     ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
     constexpr auto backup_dir = "backup";
-    const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+    const auto yuzu_amiibo_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::AmiiboDir);
     const auto file_name =
         fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
 
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index c155f19695..f327432daa 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -1330,25 +1330,25 @@ Result ISystemSettingsServer::SetPanelCrcMode(s32 panel_crc_mode) {
 
 void ISystemSettingsServer::SetupSettings() {
     auto system_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000050";
     if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) {
         ASSERT(false);
     }
 
     auto private_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000052";
     if (!LoadSettingsFile(private_dir, []() { return DefaultPrivateSettings(); })) {
         ASSERT(false);
     }
 
     auto device_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000053";
     if (!LoadSettingsFile(device_dir, []() { return DefaultDeviceSettings(); })) {
         ASSERT(false);
     }
 
     auto appln_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000054";
     if (!LoadSettingsFile(appln_dir, []() { return DefaultApplnSettings(); })) {
         ASSERT(false);
     }
@@ -1356,25 +1356,25 @@ void ISystemSettingsServer::SetupSettings() {
 
 void ISystemSettingsServer::StoreSettings() {
     auto system_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000050";
     if (!StoreSettingsFile(system_dir, m_system_settings)) {
         LOG_ERROR(Service_SET, "Failed to store System settings");
     }
 
     auto private_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000052";
     if (!StoreSettingsFile(private_dir, m_private_settings)) {
         LOG_ERROR(Service_SET, "Failed to store Private settings");
     }
 
     auto device_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000053";
     if (!StoreSettingsFile(device_dir, m_device_settings)) {
         LOG_ERROR(Service_SET, "Failed to store Device settings");
     }
 
     auto appln_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000054";
     if (!StoreSettingsFile(appln_dir, m_appln_settings)) {
         LOG_ERROR(Service_SET, "Failed to store ApplLn settings");
     }
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index f538d83b16..4439611d2e 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -39,7 +39,7 @@ PerfStats::~PerfStats() {
     std::copy(perf_history.begin() + IgnoreFrames, perf_history.begin() + current_index,
               std::ostream_iterator<double>(stream, "\n"));
 
-    const auto path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir);
+    const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::LogDir);
     // %F Date format expanded is "%Y-%m-%d"
     const auto filename = fmt::format("{:%F-%H-%M}_{:016X}.csv", *std::localtime(&t), title_id);
     const auto filepath = path / filename;
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index f70350e739..4bac8142c3 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -27,7 +27,7 @@
 namespace {
 
 std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_view timestamp) {
-    return Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / type /
+    return Common::FS::GetEdenPath(Common::FS::EdenPath::LogDir) / type /
            fmt::format("{:016X}_{}.json", title_id, timestamp);
 }
 
@@ -332,7 +332,7 @@ void Reporter::SaveErrorReport(u64 title_id, Result result,
 
 void Reporter::SaveFSAccessLog(std::string_view log_message) const {
     const auto access_log_path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "FsAccessLog.txt";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::SDMCDir) / "FsAccessLog.txt";
 
     void(Common::FS::AppendStringToFile(access_log_path, Common::FS::FileType::TextFile,
                                         log_message));
@@ -352,7 +352,7 @@ void Reporter::SaveUserReport() const {
 
 void Reporter::ClearFSAccessLog() const {
     const auto access_log_path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "FsAccessLog.txt";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::SDMCDir) / "FsAccessLog.txt";
 
     Common::FS::IOFile access_log_file{access_log_path, Common::FS::FileAccessMode::Write,
                                        Common::FS::FileType::TextFile};
diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp
index 326267e774..fa1383436e 100644
--- a/src/frontend_common/config.cpp
+++ b/src/frontend_common/config.cpp
@@ -25,7 +25,7 @@ Config::Config(const ConfigType config_type)
     : type(config_type), global{config_type == ConfigType::GlobalConfig} {}
 
 void Config::Initialize(const std::string& config_name) {
-    const std::filesystem::path fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
+    const std::filesystem::path fs_config_loc = FS::GetEdenPath(FS::EdenPath::ConfigDir);
     const auto config_file = fmt::format("{}.ini", config_name);
 
     switch (type) {
@@ -51,7 +51,7 @@ void Config::Initialize(const std::string& config_name) {
 
 void Config::Initialize(const std::optional<std::string> config_path) {
     const std::filesystem::path default_sdl_config_path =
-        FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
+        FS::GetEdenPath(FS::EdenPath::ConfigDir) / "sdl2-config.ini";
     config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
     void(FS::CreateParentDir(config_loc));
     SetUpIni();
@@ -275,11 +275,11 @@ void Config::ReadCoreValues() {
 void Config::ReadDataStorageValues() {
     BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
 
-    FS::SetYuzuPath(FS::YuzuPath::NANDDir, ReadStringSetting(std::string("nand_directory")));
-    FS::SetYuzuPath(FS::YuzuPath::SDMCDir, ReadStringSetting(std::string("sdmc_directory")));
-    FS::SetYuzuPath(FS::YuzuPath::LoadDir, ReadStringSetting(std::string("load_directory")));
-    FS::SetYuzuPath(FS::YuzuPath::DumpDir, ReadStringSetting(std::string("dump_directory")));
-    FS::SetYuzuPath(FS::YuzuPath::TASDir, ReadStringSetting(std::string("tas_directory")));
+    FS::SetEdenPath(FS::EdenPath::NANDDir, ReadStringSetting(std::string("nand_directory")));
+    FS::SetEdenPath(FS::EdenPath::SDMCDir, ReadStringSetting(std::string("sdmc_directory")));
+    FS::SetEdenPath(FS::EdenPath::LoadDir, ReadStringSetting(std::string("load_directory")));
+    FS::SetEdenPath(FS::EdenPath::DumpDir, ReadStringSetting(std::string("dump_directory")));
+    FS::SetEdenPath(FS::EdenPath::TASDir, ReadStringSetting(std::string("tas_directory")));
 
     ReadCategory(Settings::Category::DataStorage);
 
@@ -372,7 +372,7 @@ void Config::ReadScreenshotValues() {
     BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots));
 
     ReadCategory(Settings::Category::Screenshots);
-    FS::SetYuzuPath(FS::YuzuPath::ScreenshotsDir,
+    FS::SetEdenPath(FS::EdenPath::ScreenshotsDir,
                     ReadStringSetting(std::string("screenshot_path")));
 
     EndGroup();
@@ -578,16 +578,16 @@ void Config::SaveCoreValues() {
 void Config::SaveDataStorageValues() {
     BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
 
-    WriteStringSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir),
-                       std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
-    WriteStringSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir),
-                       std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
-    WriteStringSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir),
-                       std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
-    WriteStringSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir),
-                       std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
-    WriteStringSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir),
-                       std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir)));
+    WriteStringSetting(std::string("nand_directory"), FS::GetEdenPathString(FS::EdenPath::NANDDir),
+                       std::make_optional(FS::GetEdenPathString(FS::EdenPath::NANDDir)));
+    WriteStringSetting(std::string("sdmc_directory"), FS::GetEdenPathString(FS::EdenPath::SDMCDir),
+                       std::make_optional(FS::GetEdenPathString(FS::EdenPath::SDMCDir)));
+    WriteStringSetting(std::string("load_directory"), FS::GetEdenPathString(FS::EdenPath::LoadDir),
+                       std::make_optional(FS::GetEdenPathString(FS::EdenPath::LoadDir)));
+    WriteStringSetting(std::string("dump_directory"), FS::GetEdenPathString(FS::EdenPath::DumpDir),
+                       std::make_optional(FS::GetEdenPathString(FS::EdenPath::DumpDir)));
+    WriteStringSetting(std::string("tas_directory"), FS::GetEdenPathString(FS::EdenPath::TASDir),
+                       std::make_optional(FS::GetEdenPathString(FS::EdenPath::TASDir)));
 
     WriteCategory(Settings::Category::DataStorage);
 
@@ -681,7 +681,7 @@ void Config::SaveScreenshotValues() {
     BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots));
 
     WriteStringSetting(std::string("screenshot_path"),
-                       FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir));
+                       FS::GetEdenPathString(FS::EdenPath::ScreenshotsDir));
     WriteCategory(Settings::Category::Screenshots);
 
     EndGroup();
diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp
index 528d60b130..5a7f858f16 100644
--- a/src/input_common/drivers/tas_input.cpp
+++ b/src/input_common/drivers/tas_input.cpp
@@ -82,7 +82,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) {
     commands[player_index].clear();
 
     std::string file = Common::FS::ReadStringFromFile(
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
+        Common::FS::GetEdenPath(Common::FS::EdenPath::TASDir) /
             fmt::format("script{}-{}.txt", file_index, player_index + 1),
         Common::FS::FileType::BinaryFile);
     std::istringstream command_line(file);
@@ -137,7 +137,7 @@ void Tas::WriteTasFile(std::u8string_view file_name) {
                                    WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis));
     }
 
-    const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name;
+    const auto tas_file_name = Common::FS::GetEdenPath(Common::FS::EdenPath::TASDir) / file_name;
     const auto bytes_written =
         Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text);
     if (bytes_written == output_text.size()) {
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp
index 5d0bb9cc45..e476261e3e 100644
--- a/src/video_core/macro/macro.cpp
+++ b/src/video_core/macro/macro.cpp
@@ -28,7 +28,7 @@ MICROPROFILE_DEFINE(MacroHLE, "GPU", "Execute macro HLE", MP_RGB(128, 192, 192))
 namespace Tegra {
 
 static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
-    const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
+    const auto base_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)};
     const auto macro_dir{base_dir / "macros"};
     if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) {
         LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories");
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index c4bad6fca5..ba4e1ac210 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -260,7 +260,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
     if (title_id == 0) {
         return;
     }
-    const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir)};
+    const auto shader_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir)};
     const auto base_dir{shader_dir / fmt::format("{:016x}", title_id)};
     if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir)) {
         LOG_ERROR(Common_Filesystem, "Failed to create shader cache directories");
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index a7bba4eaba..62578cf306 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -472,7 +472,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
     if (title_id == 0) {
         return;
     }
-    const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir)};
+    const auto shader_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir)};
     const auto base_dir{shader_dir / fmt::format("{:016x}", title_id)};
     if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir)) {
         LOG_ERROR(Common_Filesystem, "Failed to create pipeline cache directories");
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 250fde96cc..baeb8b23a0 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -91,7 +91,7 @@ static std::string_view StageToPrefix(Shader::Stage stage) {
 static void DumpImpl(u64 pipeline_hash, u64 shader_hash, std::span<const u64> code,
                      [[maybe_unused]] u32 read_highest, [[maybe_unused]] u32 read_lowest,
                      u32 initial_offset, Shader::Stage stage) {
-    const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
+    const auto shader_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)};
     const auto base_dir{shader_dir / "shaders"};
     if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir)) {
         LOG_ERROR(Common_Filesystem, "Failed to create shader dump directories");
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
index aae3d40b62..a185f0a52b 100644
--- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
+++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
@@ -47,7 +47,7 @@ NsightAftermathTracker::NsightAftermathTracker() {
         LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers");
         return;
     }
-    dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / "gpucrash";
+    dump_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::LogDir) / "gpucrash";
 
     Common::FS::RemoveDirRecursively(dump_dir);
     if (!Common::FS::CreateDir(dump_dir)) {
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 021b43daf0..ef2dd57044 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -232,6 +232,9 @@ add_executable(yuzu
     vk_device_info.h
     compatdb.cpp
     compatdb.h
+    user_data_migration.cpp
+    user_data_migration.h
+
     yuzu.qrc
     yuzu.rc
 )
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp
index 66edd6acde..59133b82dd 100644
--- a/src/yuzu/applets/qt_profile_select.cpp
+++ b/src/yuzu/applets/qt_profile_select.cpp
@@ -30,7 +30,7 @@ QString FormatUserEntryText(const QString& username, Common::UUID uuid) {
 
 QString GetImagePath(Common::UUID uuid) {
     const auto path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) /
         fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString());
     return QString::fromStdString(Common::FS::PathToUTF8String(path));
 }
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index cce9b2efb2..8245c12ba2 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -57,7 +57,7 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
       default_profile{QWebEngineProfile::defaultProfile()}, global_settings{
                                                                 default_profile->settings()} {
     default_profile->setPersistentStoragePath(QString::fromStdString(Common::FS::PathToUTF8String(
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::YuzuDir) / "qtwebengine")));
+        Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir) / "qtwebengine")));
 
     QWebEngineScript gamepad;
     QWebEngineScript window_nx;
@@ -336,7 +336,7 @@ void QtNXWebEngineView::LoadExtractedFonts() {
     QWebEngineScript load_nx_font;
 
     auto fonts_dir_str = Common::FS::PathToUTF8String(
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts/");
+        Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "fonts/");
 
     std::replace(fonts_dir_str.begin(), fonts_dir_str.end(), '\\', '/');
 
diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp
index 0f6a71ab08..82b5deb51e 100644
--- a/src/yuzu/breakpad.cpp
+++ b/src/yuzu/breakpad.cpp
@@ -60,7 +60,7 @@ static void PruneDumpDirectory(const std::filesystem::path& dump_path) {
 
 void InstallCrashHandler() {
     // Write crash dumps to profile directory.
-    const auto dump_path = GetYuzuPath(Common::FS::YuzuPath::CrashDumpsDir);
+    const auto dump_path = GetEdenPath(Common::FS::EdenPath::CrashDumpsDir);
     PruneDumpDirectory(dump_path);
 
 #if defined(_WIN32)
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 5f23eea3d3..bcb8d1fc5e 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -21,7 +21,7 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
 
     connect(ui->open_log_button, &QPushButton::clicked, []() {
         const auto path =
-            QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LogDir));
+            QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir));
         QDesktopServices::openUrl(QUrl::fromLocalFile(path));
     });
 
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index ad19517546..f25f14708b 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -47,15 +47,15 @@ void ConfigureFilesystem::changeEvent(QEvent* event) {
 
 void ConfigureFilesystem::SetConfiguration() {
     ui->nand_directory_edit->setText(
-        QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir)));
+        QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)));
     ui->sdmc_directory_edit->setText(
-        QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir)));
+        QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)));
     ui->gamecard_path_edit->setText(
         QString::fromStdString(Settings::values.gamecard_path.GetValue()));
     ui->dump_path_edit->setText(
-        QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
+        QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::DumpDir)));
     ui->load_path_edit->setText(
-        QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
+        QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)));
 
     ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue());
     ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue());
@@ -68,13 +68,13 @@ void ConfigureFilesystem::SetConfiguration() {
 }
 
 void ConfigureFilesystem::ApplyConfiguration() {
-    Common::FS::SetYuzuPath(Common::FS::YuzuPath::NANDDir,
+    Common::FS::SetEdenPath(Common::FS::EdenPath::NANDDir,
                             ui->nand_directory_edit->text().toStdString());
-    Common::FS::SetYuzuPath(Common::FS::YuzuPath::SDMCDir,
+    Common::FS::SetEdenPath(Common::FS::EdenPath::SDMCDir,
                             ui->sdmc_directory_edit->text().toStdString());
-    Common::FS::SetYuzuPath(Common::FS::YuzuPath::DumpDir,
+    Common::FS::SetEdenPath(Common::FS::EdenPath::DumpDir,
                             ui->dump_path_edit->text().toStdString());
-    Common::FS::SetYuzuPath(Common::FS::YuzuPath::LoadDir,
+    Common::FS::SetEdenPath(Common::FS::EdenPath::LoadDir,
                             ui->load_path_edit->text().toStdString());
 
     Settings::values.gamecard_inserted = ui->gamecard_inserted->isChecked();
@@ -126,12 +126,12 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit)
 }
 
 void ConfigureFilesystem::ResetMetadata() {
-    if (!Common::FS::Exists(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
+    if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) /
                             "game_list/")) {
         QMessageBox::information(this, tr("Reset Metadata Cache"),
                                  tr("The metadata cache is already empty."));
     } else if (Common::FS::RemoveDirRecursively(
-                   Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "game_list")) {
+                   Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
         QMessageBox::information(this, tr("Reset Metadata Cache"),
                                  tr("The operation completed successfully."));
         UISettings::values.is_game_list_reload_pending.exchange(true);
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp
index 568775027b..078f2e8288 100644
--- a/src/yuzu/configuration/configure_per_game_addons.cpp
+++ b/src/yuzu/configuration/configure_per_game_addons.cpp
@@ -80,7 +80,7 @@ void ConfigurePerGameAddons::ApplyConfiguration() {
     std::sort(disabled_addons.begin(), disabled_addons.end());
     std::sort(current.begin(), current.end());
     if (disabled_addons != current) {
-        Common::FS::RemoveFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
+        Common::FS::RemoveFile(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) /
                                "game_list" / fmt::format("{:016X}.pv.txt", title_id));
     }
 
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index 12a04b9a0b..bf3a96b211 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -35,7 +35,7 @@ constexpr std::array<u8, 107> backup_jpeg{
 
 QString GetImagePath(const Common::UUID& uuid) {
     const auto path =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) /
         fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString());
     return QString::fromStdString(Common::FS::PathToUTF8String(path));
 }
@@ -288,7 +288,7 @@ void ConfigureProfileManager::SetUserImage() {
     }
 
     const auto raw_path = QString::fromStdString(Common::FS::PathToUTF8String(
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000010"));
+        Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000010"));
     const QFileInfo raw_info{raw_path};
     if (raw_info.exists() && !raw_info.isDir() && !QFile::remove(raw_path)) {
         QMessageBox::warning(this, tr("Error deleting file"),
diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp
index 5a545aa706..773658bf22 100644
--- a/src/yuzu/configuration/configure_tas.cpp
+++ b/src/yuzu/configuration/configure_tas.cpp
@@ -28,14 +28,14 @@ ConfigureTasDialog::~ConfigureTasDialog() = default;
 
 void ConfigureTasDialog::LoadConfiguration() {
     ui->tas_path_edit->setText(
-        QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir)));
+        QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::TASDir)));
     ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue());
     ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue());
     ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue());
 }
 
 void ConfigureTasDialog::ApplyConfiguration() {
-    Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString());
+    Common::FS::SetEdenPath(Common::FS::EdenPath::TASDir, ui->tas_path_edit->text().toStdString());
     Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked());
     Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked());
     Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked());
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index a75a1b264e..8c3bbf1af4 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -144,8 +144,8 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
     connect(ui->screenshot_path_button, &QToolButton::pressed, this, [this] {
         auto dir =
             QFileDialog::getExistingDirectory(this, tr("Select Screenshots Path..."),
-                                              QString::fromStdString(Common::FS::GetYuzuPathString(
-                                                  Common::FS::YuzuPath::ScreenshotsDir)));
+                                              QString::fromStdString(Common::FS::GetEdenPathString(
+                                                  Common::FS::EdenPath::ScreenshotsDir)));
         if (!dir.isEmpty()) {
             if (dir.back() != QChar::fromLatin1('/')) {
                 dir.append(QChar::fromLatin1('/'));
@@ -176,7 +176,7 @@ void ConfigureUi::ApplyConfiguration() {
     UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
 
     UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
-    Common::FS::SetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir,
+    Common::FS::SetEdenPath(Common::FS::EdenPath::ScreenshotsDir,
                             ui->screenshot_path_edit->text().toStdString());
 
     const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
@@ -208,7 +208,7 @@ void ConfigureUi::SetConfiguration() {
     ui->enable_screenshot_save_as->setChecked(
         UISettings::values.enable_screenshot_save_as.GetValue());
     ui->screenshot_path_edit->setText(QString::fromStdString(
-        Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
+        Common::FS::GetEdenPathString(Common::FS::EdenPath::ScreenshotsDir)));
 
     const auto height = UISettings::values.screenshot_height.GetValue();
     if (height == 0) {
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 0ff5e18c1c..df80be8252 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -14,7 +14,7 @@ namespace FS = Common::FS;
 namespace {
 
 bool ProfileExistsInFilesystem(std::string_view profile_name) {
-    return FS::Exists(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input" /
+    return FS::Exists(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "input" /
                       fmt::format("{}.ini", profile_name));
 }
 
@@ -29,7 +29,7 @@ std::filesystem::path GetNameWithoutExtension(std::filesystem::path filename) {
 } // namespace
 
 InputProfiles::InputProfiles() {
-    const auto input_profile_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input";
+    const auto input_profile_loc = FS::GetEdenPath(FS::EdenPath::ConfigDir) / "input";
 
     if (!FS::IsDir(input_profile_loc)) {
         return;
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp
index 37951b9c84..ae5b330e23 100644
--- a/src/yuzu/configuration/qt_config.cpp
+++ b/src/yuzu/configuration/qt_config.cpp
@@ -46,6 +46,7 @@ const std::array<int, 2> QtConfig::default_ringcon_analogs{{
 
 QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type)
     : Config(config_type) {
+
     Initialize(config_name);
     if (config_type != ConfigType::InputProfile) {
         ReadQtValues();
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 0cbf5f45e8..4f977b87be 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -38,7 +38,7 @@ QString GetGameListCachedObject(const std::string& filename, const std::string&
     }
 
     const auto path =
-        Common::FS::PathToUTF8String(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
+        Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) /
                                      "game_list" / fmt::format("{}.{}", filename, ext));
 
     void(Common::FS::CreateParentDirs(path));
@@ -70,7 +70,7 @@ std::pair<std::vector<u8>, std::string> GetGameListCachedObject(
     }
 
     const auto game_list_dir =
-        Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "game_list";
+        Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list";
     const auto jpeg_name = fmt::format("{}.jpeg", filename);
     const auto app_name = fmt::format("{}.appname.txt", filename);
 
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 7f52b8fbc4..8cd20a452d 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -211,7 +211,7 @@ static const QList<u64> bad_update_games{
 const int GMainWindow::max_recent_files_item;
 
 static void RemoveCachedContents() {
-    const auto cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir);
+    const auto cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
     const auto offline_fonts = cache_dir / "fonts";
     const auto offline_manual = cache_dir / "offline_web_applet_manual";
     const auto offline_legal_information = cache_dir / "offline_web_applet_legal_information";
@@ -301,15 +301,20 @@ bool GMainWindow::CheckDarkMode() {
 #endif // __unix__
 }
 
-GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan)
+GMainWindow::GMainWindow(bool has_broken_vulkan)
     : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
-      input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)},
+      input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
+      user_data_migrator{this},
       vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
       provider{std::make_unique<FileSys::ManualContentProvider>()} {
+    Common::FS::CreateEdenPaths();
+    this->config = std::make_unique<QtConfig>();
 #ifdef __unix__
     SetupSigInterrupts();
     SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue());
 #endif
+    UISettings::RestoreWindowState(config);
+
     system->Initialize();
 
     Common::Log::Initialize();
@@ -2322,7 +2327,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
     switch (target) {
     case GameListOpenTarget::SaveData: {
         open_target = tr("Save Data");
-        const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
+        const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
         auto vfs_nand_dir =
                 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
 
@@ -2378,7 +2383,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
     }
     case GameListOpenTarget::ModData: {
         open_target = tr("Mod Data");
-        path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir) /
+        path = Common::FS::GetEdenPath(Common::FS::EdenPath::LoadDir) /
                 fmt::format("{:016X}", program_id);
         break;
     }
@@ -2400,7 +2405,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
 }
 
 void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
-    const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
+    const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
     const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
     if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
         QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"),
@@ -2519,7 +2524,7 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT
         RemoveAddOnContent(program_id, type);
         break;
     }
-    Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
+    Common::FS::RemoveDirRecursively(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) /
                                      "game_list");
     game_list->PopulateAsync(UISettings::values.game_dirs);
 }
@@ -2625,7 +2630,7 @@ void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTa
             return "";
         }
     }();
-    const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
+    const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
     const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id);
     const auto target_file = shader_cache_folder_path / target_file_name;
 
@@ -2646,7 +2651,7 @@ void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTa
 void GMainWindow::RemoveVulkanDriverPipelineCache(u64 program_id) {
     static constexpr std::string_view target_file_name = "vulkan_pipelines.bin";
 
-    const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
+    const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
     const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id);
     const auto target_file = shader_cache_folder_path / target_file_name;
 
@@ -2660,7 +2665,7 @@ void GMainWindow::RemoveVulkanDriverPipelineCache(u64 program_id) {
 }
 
 void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) {
-    const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
+    const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
     const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id);
 
     if (!Common::FS::Exists(program_shader_cache_dir)) {
@@ -2683,7 +2688,7 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g
             program_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()).append(".ini")
                             : fmt::format("{:016X}.ini", program_id);
     const auto custom_config_file_path =
-            Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "custom" / config_file_name;
+            Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "custom" / config_file_name;
 
     if (!Common::FS::Exists(custom_config_file_path)) {
         QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
@@ -2701,7 +2706,7 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g
 }
 
 void GMainWindow::RemoveCacheStorage(u64 program_id) {
-    const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
+    const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
     auto vfs_nand_dir =
             vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
 
@@ -2759,8 +2764,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
     const auto base_romfs = base_nca->GetRomFS();
     const auto dump_dir =
             target == DumpRomFSTarget::Normal
-            ? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)
-            : Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents";
+            ? Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)
+            : Common::FS::GetEdenPath(Common::FS::EdenPath::SDMCDir) / "atmosphere" / "contents";
     const auto romfs_dir = fmt::format("{:016X}/romfs", title_id);
 
     const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
@@ -3018,7 +3023,7 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi
     // Get path to Yuzu icons directory & icon extension
     std::string ico_extension = "png";
 #if defined(_WIN32)
-    out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::IconsDir);
+    out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir);
     ico_extension = "ico";
 #elif defined(__linux__) || defined(__FreeBSD__)
     out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";
@@ -3141,13 +3146,13 @@ void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
     std::filesystem::path fs_path;
     if (directory == QStringLiteral("SDMC")) {
         fs_path =
-                Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "Nintendo/Contents/registered";
+                Common::FS::GetEdenPath(Common::FS::EdenPath::SDMCDir) / "Nintendo/Contents/registered";
     } else if (directory == QStringLiteral("UserNAND")) {
         fs_path =
-                Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "user/Contents/registered";
+                Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "user/Contents/registered";
     } else if (directory == QStringLiteral("SysNAND")) {
         fs_path =
-                Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/Contents/registered";
+                Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/Contents/registered";
     } else {
         fs_path = directory.toStdString();
     }
@@ -3373,7 +3378,7 @@ void GMainWindow::OnMenuInstallToNAND() {
                                     : tr("%n file(s) failed to install\n", "", failed_files.size()));
 
     QMessageBox::information(this, tr("Install Results"), install_results);
-    Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
+    Common::FS::RemoveDirRecursively(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) /
                                      "game_list");
     game_list->PopulateAsync(UISettings::values.game_dirs);
     ui->action_Install_File_NAND->setEnabled(true);
@@ -3791,11 +3796,11 @@ void GMainWindow::OnConfigure() {
             LOG_WARNING(Frontend, "Failed to remove configuration file");
         }
         if (!Common::FS::RemoveDirContentsRecursively(
-                    Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "custom")) {
+                    Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "custom")) {
             LOG_WARNING(Frontend, "Failed to remove custom configuration files");
         }
         if (!Common::FS::RemoveDirRecursively(
-                    Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "game_list")) {
+                    Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
             LOG_WARNING(Frontend, "Failed to remove game metadata cache files");
         }
 
@@ -4151,7 +4156,7 @@ void GMainWindow::LoadAmiibo(const QString& filename) {
 
 void GMainWindow::OnOpenYuzuFolder() {
     QDesktopServices::openUrl(QUrl::fromLocalFile(
-                                  QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::YuzuDir))));
+                                  QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir))));
 }
 
 void GMainWindow::OnVerifyInstalledContents() {
@@ -4366,7 +4371,7 @@ void GMainWindow::OnInstallDecryptionKeys() {
         return;
     }
 
-    const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+    const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
     for (auto key_file : source_key_files) {
         std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename();
         if (!std::filesystem::copy_file(key_file, destination_key_file,
@@ -4542,7 +4547,7 @@ void GMainWindow::OnCaptureScreenshot() {
 
     const u64 title_id = system->GetApplicationProcessProgramID();
     const auto screenshot_path =
-            QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir));
+            QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ScreenshotsDir));
     const auto date =
             QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd_hh-mm-ss-zzz"));
     QString filename = QStringLiteral("%1/%2_%3.png")
@@ -4570,7 +4575,7 @@ void GMainWindow::OnCaptureScreenshot() {
 
 // TODO: Written 2020-10-01: Remove per-game config migration code when it is irrelevant
 void GMainWindow::MigrateConfigFiles() {
-    const auto config_dir_fs_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir);
+    const auto config_dir_fs_path = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
     const QDir config_dir =
             QDir(QString::fromStdString(Common::FS::PathToUTF8String(config_dir_fs_path)));
     const QStringList config_dir_list = config_dir.entryList(QStringList(QStringLiteral("*.ini")));
@@ -5289,8 +5294,6 @@ static void SetHighDPIAttributes() {
 }
 
 int main(int argc, char* argv[]) {
-    std::unique_ptr<QtConfig> config = std::make_unique<QtConfig>();
-    UISettings::RestoreWindowState(config);
     bool has_broken_vulkan = false;
     bool is_child = false;
     if (CheckEnvVars(&is_child)) {
@@ -5315,7 +5318,7 @@ int main(int argc, char* argv[]) {
     Common::ConfigureNvidiaEnvironmentFlags();
 
     // Init settings params
-    QCoreApplication::setOrganizationName(QStringLiteral("yuzu"));
+    QCoreApplication::setOrganizationName(QStringLiteral("eden"));
     QCoreApplication::setApplicationName(QStringLiteral("eden"));
 
 #ifdef _WIN32
@@ -5340,7 +5343,7 @@ int main(int argc, char* argv[]) {
 
     // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop
     // suffix.
-    QGuiApplication::setDesktopFileName(QStringLiteral("org.yuzu_emu.yuzu"));
+    QGuiApplication::setDesktopFileName(QStringLiteral("org.eden_emu.eden"));
 #endif
 
     SetHighDPIAttributes();
@@ -5374,7 +5377,7 @@ int main(int argc, char* argv[]) {
     // generating shaders
     setlocale(LC_ALL, "C");
 
-    GMainWindow main_window{std::move(config), has_broken_vulkan};
+    GMainWindow main_window{has_broken_vulkan};
     // After settings have been loaded by GMainWindow, apply the filter
     main_window.show();
 
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index af01d94e3b..a6e3bbaa6c 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -18,6 +18,7 @@
 #include "configuration/qt_config.h"
 #include "frontend_common/content_manager.h"
 #include "input_common/drivers/tas_input.h"
+#include "user_data_migration.h"
 #include "yuzu/compatibility_list.h"
 #include "yuzu/hotkeys.h"
 #include "yuzu/util/controller_navigation.h"
@@ -167,7 +168,7 @@ class GMainWindow : public QMainWindow {
 public:
     void filterBarSetChecked(bool state);
     void UpdateUITheme();
-    explicit GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan);
+    explicit GMainWindow(bool has_broken_vulkan);
     ~GMainWindow() override;
 
     bool DropAction(QDropEvent* event);
@@ -508,6 +509,7 @@ private:
     QSlider* volume_slider = nullptr;
     QTimer status_bar_update_timer;
 
+    UserDataMigrator user_data_migrator;
     std::unique_ptr<QtConfig> config;
 
     // Whether emulation is currently running in yuzu.
diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp
index 94c99274dd..2669e3a7ab 100644
--- a/src/yuzu/play_time_manager.cpp
+++ b/src/yuzu/play_time_manager.cpp
@@ -26,7 +26,7 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
     if (!uuid.has_value()) {
         return std::nullopt;
     }
-    return Common::FS::GetYuzuPath(Common::FS::YuzuPath::PlayTimeDir) /
+    return Common::FS::GetEdenPath(Common::FS::EdenPath::PlayTimeDir) /
            uuid->RawString().append(".bin");
 }
 
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index 7bb7e95af5..02d6bc9006 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -57,7 +57,7 @@ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
 
 void SaveWindowState() {
     const auto window_state_config_loc =
-        FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini");
+        FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini");
 
     void(FS::CreateParentDir(window_state_config_loc));
     QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
@@ -73,12 +73,12 @@ void SaveWindowState() {
 
 void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) {
     const auto window_state_config_loc =
-        FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini");
+        FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini");
 
     // Migrate window state from old location
     if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) {
         const auto config_loc =
-            FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "qt-config.ini");
+            FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "qt-config.ini");
         QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat);
 
         config.beginGroup(QStringLiteral("UI"));
diff --git a/src/yuzu/user_data_migration.cpp b/src/yuzu/user_data_migration.cpp
new file mode 100644
index 0000000000..d890550222
--- /dev/null
+++ b/src/yuzu/user_data_migration.cpp
@@ -0,0 +1,168 @@
+// Copyright Citra Emulator Project / Azahar Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <QMessageBox>
+#include <QPushButton>
+#include <QString>
+#include <QTranslator>
+#include "common/fs/path_util.h"
+#include "user_data_migration.h"
+
+// Needs to be included at the end due to https://bugreports.qt.io/browse/QTBUG-73263
+#include <QCheckBox>
+#include <filesystem>
+
+namespace fs = std::filesystem;
+
+UserDataMigrator::UserDataMigrator(QMainWindow* main_window) {
+    // NOTE: Logging is not initialized yet, do not produce logs here.
+
+    // Check migration if config directory does not exist
+    // TODO: ProfileManager messes with us a bit here, and force-creates the /nand/system/save/8000000000000010/su/avators/profiles.dat
+    // file. Find a way to reorder operations and have it create after this guy runs.
+    if (!fs::is_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir))) {
+        ShowMigrationPrompt(main_window);
+    }
+}
+
+void UserDataMigrator::ShowMigrationPrompt(QMainWindow* main_window) {
+    namespace fs = std::filesystem;
+
+    const QString migration_prompt_message =
+        main_window->tr("Would you like to migrate your data for use in Eden?\n"
+                        "Select the corresponding button to migrate data from that emulator.\n"
+                        "(This may take a while; The old data will not be deleted)\n\n"
+                        "Clearing shader cache is recommended for all users.\nDo not uncheck unless you know what you're doing.");
+
+    bool any_found = false;
+
+    QMessageBox migration_prompt;
+    migration_prompt.setWindowTitle(main_window->tr("Migration"));
+    migration_prompt.setIcon(QMessageBox::Information);
+
+    QCheckBox *clear_shaders = new QCheckBox(&migration_prompt);
+    clear_shaders->setText(main_window->tr("Clear Shader Cache"));
+    clear_shaders->setChecked(true);
+    migration_prompt.setCheckBox(clear_shaders);
+
+    // Reflection would make this code 10x better
+    // but for now... MACRO MADNESS!!!!
+    QMap<QString, bool> found;
+    QMap<QString, LegacyEmu> legacyMap;
+    QMap<QString, QAbstractButton *> buttonMap;
+
+#define EMU_MAP(name) const bool name##_found = fs::is_directory(Common::FS::GetLegacyPath(Common::FS::LegacyPath::name##Dir)); \
+    legacyMap[main_window->tr(#name)] = LegacyEmu::name; \
+    found[main_window->tr(#name)] = name##_found; \
+    if (name##_found) any_found = true;
+
+    EMU_MAP(Citron)
+    EMU_MAP(Sudachi)
+    EMU_MAP(Yuzu)
+    EMU_MAP(Suyu)
+
+#undef EMU_MAP
+
+    if (any_found) {
+        QString promptText = main_window->tr("Eden has detected user data for the following emulators:");
+        QMapIterator iter(found);
+
+        while (iter.hasNext()) {
+            iter.next();
+            if (!iter.value()) continue;
+
+            buttonMap[iter.key()] = migration_prompt.addButton(iter.key(), QMessageBox::YesRole);
+            promptText.append(main_window->tr("\n- %1").arg(iter.key()));
+        }
+
+        promptText.append(main_window->tr("\n\n"));
+
+        migration_prompt.setText(promptText + migration_prompt_message);
+        migration_prompt.addButton(QMessageBox::No);
+
+        migration_prompt.exec();
+
+        QMapIterator buttonIter(buttonMap);
+
+        while (buttonIter.hasNext()) {
+            buttonIter.next();
+            if (buttonIter.value() == migration_prompt.clickedButton()) {
+                MigrateUserData(main_window, legacyMap[iter.key()], clear_shaders->isChecked());
+                return;
+            }
+        }
+
+        // If we're here, the user chose not to migrate
+        ShowMigrationCancelledMessage(main_window);
+    }
+
+    else // no other data was found
+        return;
+}
+
+void UserDataMigrator::ShowMigrationCancelledMessage(QMainWindow* main_window) {
+    QMessageBox::information(
+        main_window, main_window->tr("Migration"),
+        main_window
+            ->tr("You can manually re-trigger this prompt by deleting the "
+                 "new config directory:\n"
+                 "%1")
+            .arg(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ConfigDir))),
+        QMessageBox::Ok);
+}
+
+void UserDataMigrator::MigrateUserData(QMainWindow* main_window,
+                                       const LegacyEmu selected_legacy_emu, const bool clear_shader_cache) {
+    namespace fs = std::filesystem;
+    const auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive;
+
+    std::string legacy_user_dir;
+    std::string legacy_config_dir;
+    std::string legacy_cache_dir;
+
+#define LEGACY_EMU(emu) case LegacyEmu::emu: \
+    legacy_user_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##Dir).string(); \
+    legacy_config_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##ConfigDir).string(); \
+    legacy_cache_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##CacheDir).string(); \
+    break;
+
+    switch (selected_legacy_emu) {
+        LEGACY_EMU(Citron)
+        LEGACY_EMU(Sudachi)
+        LEGACY_EMU(Yuzu)
+        LEGACY_EMU(Suyu)
+    }
+
+#undef LEGACY_EMU
+
+    fs::copy(legacy_user_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir), copy_options);
+
+    if (fs::is_directory(legacy_config_dir)) {
+        fs::copy(legacy_config_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir),
+                 copy_options);
+    }
+    if (fs::is_directory(legacy_cache_dir)) {
+        fs::copy(legacy_cache_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir),
+                 copy_options);
+    }
+
+    // Delete and re-create shader dir
+    if (clear_shader_cache) {
+        fs::remove_all(Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir));
+        fs::create_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir));
+    }
+
+    QMessageBox::information(
+        main_window, main_window->tr("Migration"),
+        main_window
+            ->tr("Data was migrated successfully.\n\n"
+                 "If you wish to clean up the files which were left in the old "
+                 "data location, you can do so by deleting the following directory:\n"
+                 "%1")
+            .arg(QString::fromStdString(legacy_user_dir)),
+        QMessageBox::Ok);
+}
diff --git a/src/yuzu/user_data_migration.h b/src/yuzu/user_data_migration.h
new file mode 100644
index 0000000000..098f19280b
--- /dev/null
+++ b/src/yuzu/user_data_migration.h
@@ -0,0 +1,27 @@
+// Copyright Citra Emulator Project / Azahar Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <QMainWindow>
+
+class UserDataMigrator {
+public:
+    UserDataMigrator(QMainWindow* main_window);
+
+private:
+    enum class LegacyEmu {
+        Citron,
+        Sudachi,
+        Yuzu,
+        Suyu,
+    };
+
+    void ShowMigrationPrompt(QMainWindow* main_window);
+    void ShowMigrationCancelledMessage(QMainWindow* main_window);
+    void MigrateUserData(QMainWindow* main_window, const LegacyEmu selected_legacy_emu, const bool clear_shader_cache);
+};