diff --git a/src/core/core.cpp b/src/core/core.cpp
index 05af68f22..28038ff6f 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,6 +5,7 @@
 #include <memory>
 #include <utility>
 #include "common/logging/log.h"
+#include "common/string_util.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/gdbstub/gdbstub.h"
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 5440cdefb..766fef254 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -427,7 +427,7 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
     }
     Refresh();
     return std::find_if(yuzu_meta.begin(), yuzu_meta.end(),
-                        [&cnmt](const std::pair<const u64, CNMT>& kv) {
+                        [&cnmt](const std::pair<u64, CNMT>& kv) {
                             return kv.second.GetType() == cnmt.GetType() &&
                                    kv.second.GetTitleID() == cnmt.GetTitleID();
                         }) != yuzu_meta.end();
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 94fb8ae6a..c48191486 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -24,6 +24,7 @@
 #include "common/string_util.h"
 #include "core/core.h"
 #include "core/crypto/key_manager.h"
+#include "core/file_sys/card_image.h"
 #include "core/file_sys/vfs_real.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/loader/loader.h"
@@ -114,6 +115,9 @@ GMainWindow::GMainWindow()
                        .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc));
     show();
 
+    // Necessary to load titles from nand in gamelist.
+    Service::FileSystem::RegisterBIS(std::make_unique<FileSys::BISFactory>(vfs->OpenDirectory(
+        FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite)));
     game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
 
     // Show one-time "callout" messages to the user
@@ -309,6 +313,8 @@ void GMainWindow::ConnectMenuEvents() {
     // File
     connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile);
     connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
+    connect(ui.action_Install_File_NAND, &QAction::triggered, this,
+            &GMainWindow::OnMenuInstallToNAND);
     connect(ui.action_Select_Game_List_Root, &QAction::triggered, this,
             &GMainWindow::OnMenuSelectGameListRoot);
     connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close);
@@ -612,6 +618,89 @@ void GMainWindow::OnMenuLoadFolder() {
     }
 }
 
+void GMainWindow::OnMenuInstallToNAND() {
+    const static QString file_filter =
+        tr("Installable Switch File (*.nca *.xci);;Nintendo Content Archive (*.nca);;NX Cartridge "
+           "Image (*.xci)");
+    QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
+                                                    UISettings::values.roms_path, file_filter);
+    if (!filename.isEmpty()) {
+        if (filename.endsWith("xci", Qt::CaseInsensitive)) {
+            const auto xci = std::make_shared<FileSys::XCI>(
+                vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
+            if (xci->GetStatus() != Loader::ResultStatus::Success) {
+                QMessageBox::critical(
+                    this, tr("Failed to Install XCI"),
+                    tr("The XCI file you provided is invalid. Please double-check your encryption "
+                       "keys and the file and try again."));
+                return;
+            }
+            if (!Service::FileSystem::GetUserNANDContents()->InstallEntry(xci)) {
+                QMessageBox::critical(
+                    this, tr("Failed to Install XCI"),
+                    tr("There was an error while attempting to install the provided XCI file. It "
+                       "could have an incorrect format or be missing a metadata entry. Please "
+                       "double-check your file and try again."));
+            } else {
+                QMessageBox::information(this, tr("Successfully Installed XCI"),
+                                         tr("The file was successfully installed."));
+                game_list->PopulateAsync(UISettings::values.gamedir,
+                                         UISettings::values.gamedir_deepscan);
+            }
+        } else {
+            const auto nca = std::make_shared<FileSys::NCA>(
+                vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
+            if (nca->GetStatus() != Loader::ResultStatus::Success) {
+                QMessageBox::critical(
+                    this, tr("Failed to Install NCA"),
+                    tr("The NCA file you provided is invalid. Please double-check your encryption "
+                       "keys and the file and try again."));
+                return;
+            }
+
+            const static QStringList tt_options{"System Application",
+                                                "System Archive",
+                                                "System Application Update",
+                                                "Firmware Package (Type A)",
+                                                "Firmware Package (Type B)",
+                                                "Game",
+                                                "Game Update",
+                                                "Game DLC",
+                                                "Delta Title"};
+            bool ok;
+            const auto item = QInputDialog::getItem(
+                this, tr("Select NCA Install Type..."),
+                tr("Please select the type of title you would like to install this NCA as:\n(In "
+                   "most instances, the default 'Game' is fine.)"),
+                tt_options, 5, false, &ok);
+
+            auto index = tt_options.indexOf(item);
+            if (!ok || index == -1) {
+                QMessageBox::critical(this, tr("Failed to Install NCA"),
+                                      tr("The title type you selected for the NCA is invalid."));
+                return;
+            }
+
+            if (index >= 5)
+                index += 0x80;
+
+            if (!Service::FileSystem::GetUserNANDContents()->InstallEntry(
+                    nca, static_cast<FileSys::TitleType>(index))) {
+                QMessageBox::critical(this, tr("Failed to Install NCA"),
+                                      tr("There was an error while attempting to install the "
+                                         "provided NCA file. An error might have occured creating "
+                                         "the metadata file or parsing the NCA. Please "
+                                         "double-check your file and try again."));
+            } else {
+                QMessageBox::information(this, tr("Successfully Installed NCA"),
+                                         tr("The file was successfully installed."));
+                game_list->PopulateAsync(UISettings::values.gamedir,
+                                         UISettings::values.gamedir_deepscan);
+            }
+        }
+    }
+}
+
 void GMainWindow::OnMenuSelectGameListRoot() {
     QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
     if (!dir_path.isEmpty()) {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 74487c58c..5f4d2ab9a 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -125,6 +125,7 @@ private slots:
     void OnGameListOpenSaveFolder(u64 program_id);
     void OnMenuLoadFile();
     void OnMenuLoadFolder();
+    void OnMenuInstallToNAND();
     /// Called whenever a user selects the "File->Select Game List Root" menu item
     void OnMenuSelectGameListRoot();
     void OnMenuRecentFile();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 22c4cad08..a3bfb2af3 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -57,6 +57,8 @@
       <string>Recent Files</string>
      </property>
     </widget>
+     <addaction name="action_Install_File_NAND" />
+     <addaction name="separator"/>
     <addaction name="action_Load_File"/>
     <addaction name="action_Load_Folder"/>
     <addaction name="separator"/>
@@ -102,6 +104,11 @@
    <addaction name="menu_View"/>
    <addaction name="menu_Help"/>
   </widget>
+   <action name="action_Install_File_NAND">
+     <property name="text">
+       <string>Install File to NAND...</string>
+     </property>
+   </action>
   <action name="action_Load_File">
    <property name="text">
     <string>Load File...</string>