tuckerwales/nslibrary

Self-hosted library for your own Nintendo Switch dumps. Scan folders of NSP, NSZ, XCI, XCZ, and homebrew NRO files, fill in metadata, spot missing or duplicate content, and send titles to a modded Switch over LAN.

TypeScript

0

2 commits

updated Sep 19, 2026

See the code
nintendo-switch
self-hosted
switch
switch-homebrew

See what people are saying (1)

README

NSLibrary

CI License

Self-hosted library for your own Nintendo Switch dumps. Scan folders of NSP, NSZ, XCI, XCZ, and homebrew NRO files, fill in metadata, spot missing or duplicate content, and send titles to a modded Switch over LAN.

There are no download sources, no shop scraping, and no title keys handed out. Keys (prod.keys) come from your own console, stay on the server, and are optional.

The web library, listing four games with their base, update, and DLC badges

This project is for content you dumped yourself, from your own console and your own cartridges. It will not help you obtain games, keys, or firmware, and requests to add that are out of scope permanently. See CONTRIBUTING.md.

Features

  • Library server — Fastify + SQLite. Walks library folders (read-only), watches for changes, and groups base games, updates, DLC, and homebrew.
  • Web UI — React app served by the same process: library, homebrew, problems, devices, folders, and settings.
  • Metadata — Container listings and tickets need no keys. Names, icons, firmware requirements, and NCA hashes need prod.keys dumped from your console. Optional titledb (a URL or file you supply, refreshed daily if it's a URL) fills in names, which game DLC belongs to, and latest-version numbers only.
  • Device API — A paired Switch browses the catalog and claims install jobs. The console always initiates; “Send to Switch” queues work for it to pick up.
  • Discovery — UDP NSLIB?1 on port 8466, plus mDNS _nslibrary._tcp so the server shows up in Bonjour/Avahi browsers. You can always type an IP by hand.
  • USB — A Switch plugged into the computer running NSLibrary (Electron, or Docker on Linux with device passthrough) uses the same device API inside NSLU frames. Transfers time out so cancel and unplug can interrupt a job.
  • Desktop app — Electron wraps the same server: tray, native folder picker, USB, auto sign-in on this machine.
  • Demo data — Synthetic containers and a fake keyset so the UI is usable without real dumps. No copyrighted content.

The Switch homebrew client (C++ / Borealis) streams NSP, NSZ, XCI, and XCZ installs into SD or NAND without copying the whole file to the SD card first. Connect over LAN HTTP or USB.

The Switch app's library grid, showing five games with their installed version under each icon

Quick start

Borealis is a submodule, so clone recursively (git submodule update --init --recursive if you already cloned):

git clone --recursive https://github.com/tuckerwales/nslibrary.git
cd nslibrary

Docker (Node 22 image, linux/amd64 and linux/arm64, port 8465):

docker compose up --build

Open http://localhost:8465 and create the admin account. The first run asks for a setup token, which the server prints to its log on boot (docker compose logs nslibrary):

  Setup token: K7M2X-9PQRT-4WHJN-6DFYB

Set NSLIB_SETUP_TOKEN to choose your own. Then browse the demo library, mount your dumps read-only as /library/games, and add that path under Folders.

Without Docker (Node ≥ 22.15, pnpm 12):

pnpm install
pnpm seed
NSLIB_SEED=true \
  NSLIB_SEED_DIR="$PWD/data/demo-library" \
  NSLIB_SEED_KEYS="$PWD/data/keys/prod.keys" \
  pnpm start

Then pnpm --filter @nslib/web build so the server can serve the UI, or run pnpm dev:web alongside pnpm start / pnpm dev:server and use the Vite proxy on http://localhost:5173.

Production deploys (Coolify, volumes, PUID/PGID) are in docs/deploy.md.

Repository

pnpm workspaces. Shared types live in @nslib/shared; parsers never write into library folders.

PathPackageRole
packages/shared@nslib/sharedZod schemas, error codes, USB frame constants, golden protocol files
packages/formats@nslib/formatsPFS0, HFS0/XCI, NCA, CNMT, NACP, ticket, NCZ, NRO, keyset
packages/fixtures@nslib/fixturesSynthetic containers encrypted with a generated fake keyset
packages/server@nslib/serverHTTP APIs, scanner, SQLite (Drizzle), keys, titledb, UDP discovery
packages/web@nslib/webReact + Vite + TanStack Query UI
packages/device-sim@nslib/device-simCLI fake Switch for the device API (nslib-sim)
packages/usb-host@nslib/usb-hostUSB frame session and node-usb attach
packages/electron@nslib/desktopElectron window, tray, USB on the desktop
switch/libnx + Borealis client, host-native C++ tests
docker/Image entrypoint and compose overlay
docs/Device API, USB frames, keys, deploy

Development

pnpm install
pnpm test          # Vitest across packages
pnpm typecheck
pnpm lint
pnpm format
pnpm dev:server    # API + scanner on :8465
pnpm dev:web       # UI on :5173, proxies /api to the server

nslib-sim talks to a running server the way a Switch would:

pnpm --filter @nslib/device-sim start -- pair --code 123456
pnpm --filter @nslib/device-sim start -- hello --token <token>

Switch client

Host-native tests (no devkitPro) cover PFS0, HFS0/XCI, NCZ, CNMT, tickets, JSON, the device-API codec, USB frames, and the install pipeline against the same golden files as TypeScript:

pnpm test:switch

The .nro needs devkitPro (switch-curl, switch-libzstd). From the repo root:

./scripts/build-switch.sh

See docs/switch.md for pairing, USB, nxlink -s, and NSP/NSZ/XCI installs to SD or NAND. Host tests need libzstd-dev. Desktop: pnpm dev:desktop (see docs/desktop.md).

Configuration

VariableDefaultMeaning
NSLIB_HOST0.0.0.0Bind address
NSLIB_PORT / PORT8465HTTP (web UI, /api/v1, /api/device/v1)
NSLIB_DATA_DIRdataSQLite, keys, icon cache. Docker: /data
NSLIB_WEB_DIRpackages/server/public or packages/web/distBuilt UI; unset serves API only
NSLIB_TRUST_PROXYoffSet true behind Coolify / Traefik
NSLIB_POLLINGoffPoll library folders (NFS/SMB) instead of inotify
NSLIB_DISCOVERYon0 / false disables UDP discovery and mDNS advertising
NSLIB_DISCOVERY_PORT8466UDP port for NSLIB?1
NSLIB_SETUP_TOKENgeneratedCreating the admin account asks for this value. Unset, the server generates one per boot and logs it, so a server reachable before you've signed up can't be claimed by whoever opens it first
NSLIB_SERVER_NAMENSLibraryShown in hello and discovery
NSLIB_SEEDoff (on in the image)Attach the demo library on first boot if no folders exist
NSLIB_SEED_DIR / NSLIB_SEED_KEYSDemo library path and matching fake prod.keys
PUID / PGID1000Docker user that owns /data
NSLIB_LOG_LEVELinfoFastify log level
NSLIB_TLS_KEY / NSLIB_TLS_CERTPEM files for optional HTTPS (LAN without a reverse proxy)
NSLIB_NRO_PATHdata/update/nslibrary.nro if presentA signed release mirrored here, so consoles without internet can update (needs update.json and update.json.sig beside it)
NSLIB_FORWARDER_MAINdata/forwarder/main if presentExeFS main for the HOME-menu NSP

The server never writes into library folders. Missing files are marked, then purged after 30 days.

Keys

Upload prod.keys in Settings (or PUT /api/v1/keys). Stored at <dataDir>/keys/prod.keys with mode 0600. The API reports which names are present; key material is never returned, logged, or sent to a device.

Without keys the library still lists files from containers, tickets, and filenames, and labels that metadata as unverified. Details: docs/keys.md.

Documentation

  • Architecture — how the pieces fit together, and why
  • Deploy — Docker image, Coolify, volumes
  • Device API — pairing, catalog, jobs, Range downloads
  • USB protocol — frame layout (same messages as HTTP)
  • Keysprod.keys and filename mode
  • Switch updates — one channel of signed .nro releases, fetched from GitHub or mirrored on your server

Contributing

Issues and pull requests are welcome — start with CONTRIBUTING.md, which covers setup, house style, and the things this project will not accept. Security vulnerabilities go through SECURITY.md rather than the issue tracker.

Licence

Apache License 2.0. Third-party components, including Borealis, TweetNaCl, libnx, the devkitPro portlibs, and the bundled Archivo font, are listed in THIRD-PARTY.md.

NSLibrary is an independent, unofficial project. It is not affiliated with, endorsed by, or associated with Nintendo. Nintendo Switch is a trademark of Nintendo. All product names, logos, and brands are the property of their respective owners, and are used only to describe what this software interoperates with.

NSLibrary is a file manager and a transfer tool. It ships no games, no keys, no firmware, and no copyrighted Nintendo material of any kind; every test fixture in this repository is synthetic and generated from scratch. It provides no way to obtain content, and does not circumvent any protection measure — prod.keys must already be extracted from a console you own, and is optional.

What you do with it is your responsibility. Dumping content you own is treated differently in different countries; downloading or sharing content you do not own is not something this project supports, and running modified system software may violate Nintendo's terms of service and can get a console banned from online services.

Contributors

tuckerwales

2 commits

tuckerwales/nslibrary

Self-hosted library for your own Nintendo Switch dumps. Scan folders of NSP, NSZ, XCI, XCZ, and homebrew NRO files, fill in metadata, spot missing or duplicate content, and send titles to a modded Switch over LAN.

TypeScript

0

2 commits

updated Sep 19, 2026

See the code
nintendo-switch
self-hosted
switch
switch-homebrew

See what people are saying (1)

README

NSLibrary

CI License

Self-hosted library for your own Nintendo Switch dumps. Scan folders of NSP, NSZ, XCI, XCZ, and homebrew NRO files, fill in metadata, spot missing or duplicate content, and send titles to a modded Switch over LAN.

There are no download sources, no shop scraping, and no title keys handed out. Keys (prod.keys) come from your own console, stay on the server, and are optional.

The web library, listing four games with their base, update, and DLC badges

This project is for content you dumped yourself, from your own console and your own cartridges. It will not help you obtain games, keys, or firmware, and requests to add that are out of scope permanently. See CONTRIBUTING.md.

Features

  • Library server — Fastify + SQLite. Walks library folders (read-only), watches for changes, and groups base games, updates, DLC, and homebrew.
  • Web UI — React app served by the same process: library, homebrew, problems, devices, folders, and settings.
  • Metadata — Container listings and tickets need no keys. Names, icons, firmware requirements, and NCA hashes need prod.keys dumped from your console. Optional titledb (a URL or file you supply, refreshed daily if it's a URL) fills in names, which game DLC belongs to, and latest-version numbers only.
  • Device API — A paired Switch browses the catalog and claims install jobs. The console always initiates; “Send to Switch” queues work for it to pick up.
  • Discovery — UDP NSLIB?1 on port 8466, plus mDNS _nslibrary._tcp so the server shows up in Bonjour/Avahi browsers. You can always type an IP by hand.
  • USB — A Switch plugged into the computer running NSLibrary (Electron, or Docker on Linux with device passthrough) uses the same device API inside NSLU frames. Transfers time out so cancel and unplug can interrupt a job.
  • Desktop app — Electron wraps the same server: tray, native folder picker, USB, auto sign-in on this machine.
  • Demo data — Synthetic containers and a fake keyset so the UI is usable without real dumps. No copyrighted content.

The Switch homebrew client (C++ / Borealis) streams NSP, NSZ, XCI, and XCZ installs into SD or NAND without copying the whole file to the SD card first. Connect over LAN HTTP or USB.

The Switch app's library grid, showing five games with their installed version under each icon

Quick start

Borealis is a submodule, so clone recursively (git submodule update --init --recursive if you already cloned):

git clone --recursive https://github.com/tuckerwales/nslibrary.git
cd nslibrary

Docker (Node 22 image, linux/amd64 and linux/arm64, port 8465):

docker compose up --build

Open http://localhost:8465 and create the admin account. The first run asks for a setup token, which the server prints to its log on boot (docker compose logs nslibrary):

  Setup token: K7M2X-9PQRT-4WHJN-6DFYB

Set NSLIB_SETUP_TOKEN to choose your own. Then browse the demo library, mount your dumps read-only as /library/games, and add that path under Folders.

Without Docker (Node ≥ 22.15, pnpm 12):

pnpm install
pnpm seed
NSLIB_SEED=true \
  NSLIB_SEED_DIR="$PWD/data/demo-library" \
  NSLIB_SEED_KEYS="$PWD/data/keys/prod.keys" \
  pnpm start

Then pnpm --filter @nslib/web build so the server can serve the UI, or run pnpm dev:web alongside pnpm start / pnpm dev:server and use the Vite proxy on http://localhost:5173.

Production deploys (Coolify, volumes, PUID/PGID) are in docs/deploy.md.

Repository

pnpm workspaces. Shared types live in @nslib/shared; parsers never write into library folders.

PathPackageRole
packages/shared@nslib/sharedZod schemas, error codes, USB frame constants, golden protocol files
packages/formats@nslib/formatsPFS0, HFS0/XCI, NCA, CNMT, NACP, ticket, NCZ, NRO, keyset
packages/fixtures@nslib/fixturesSynthetic containers encrypted with a generated fake keyset
packages/server@nslib/serverHTTP APIs, scanner, SQLite (Drizzle), keys, titledb, UDP discovery
packages/web@nslib/webReact + Vite + TanStack Query UI
packages/device-sim@nslib/device-simCLI fake Switch for the device API (nslib-sim)
packages/usb-host@nslib/usb-hostUSB frame session and node-usb attach
packages/electron@nslib/desktopElectron window, tray, USB on the desktop
switch/libnx + Borealis client, host-native C++ tests
docker/Image entrypoint and compose overlay
docs/Device API, USB frames, keys, deploy

Development

pnpm install
pnpm test          # Vitest across packages
pnpm typecheck
pnpm lint
pnpm format
pnpm dev:server    # API + scanner on :8465
pnpm dev:web       # UI on :5173, proxies /api to the server

nslib-sim talks to a running server the way a Switch would:

pnpm --filter @nslib/device-sim start -- pair --code 123456
pnpm --filter @nslib/device-sim start -- hello --token <token>

Switch client

Host-native tests (no devkitPro) cover PFS0, HFS0/XCI, NCZ, CNMT, tickets, JSON, the device-API codec, USB frames, and the install pipeline against the same golden files as TypeScript:

pnpm test:switch

The .nro needs devkitPro (switch-curl, switch-libzstd). From the repo root:

./scripts/build-switch.sh

See docs/switch.md for pairing, USB, nxlink -s, and NSP/NSZ/XCI installs to SD or NAND. Host tests need libzstd-dev. Desktop: pnpm dev:desktop (see docs/desktop.md).

Configuration

VariableDefaultMeaning
NSLIB_HOST0.0.0.0Bind address
NSLIB_PORT / PORT8465HTTP (web UI, /api/v1, /api/device/v1)
NSLIB_DATA_DIRdataSQLite, keys, icon cache. Docker: /data
NSLIB_WEB_DIRpackages/server/public or packages/web/distBuilt UI; unset serves API only
NSLIB_TRUST_PROXYoffSet true behind Coolify / Traefik
NSLIB_POLLINGoffPoll library folders (NFS/SMB) instead of inotify
NSLIB_DISCOVERYon0 / false disables UDP discovery and mDNS advertising
NSLIB_DISCOVERY_PORT8466UDP port for NSLIB?1
NSLIB_SETUP_TOKENgeneratedCreating the admin account asks for this value. Unset, the server generates one per boot and logs it, so a server reachable before you've signed up can't be claimed by whoever opens it first
NSLIB_SERVER_NAMENSLibraryShown in hello and discovery
NSLIB_SEEDoff (on in the image)Attach the demo library on first boot if no folders exist
NSLIB_SEED_DIR / NSLIB_SEED_KEYSDemo library path and matching fake prod.keys
PUID / PGID1000Docker user that owns /data
NSLIB_LOG_LEVELinfoFastify log level
NSLIB_TLS_KEY / NSLIB_TLS_CERTPEM files for optional HTTPS (LAN without a reverse proxy)
NSLIB_NRO_PATHdata/update/nslibrary.nro if presentA signed release mirrored here, so consoles without internet can update (needs update.json and update.json.sig beside it)
NSLIB_FORWARDER_MAINdata/forwarder/main if presentExeFS main for the HOME-menu NSP

The server never writes into library folders. Missing files are marked, then purged after 30 days.

Keys

Upload prod.keys in Settings (or PUT /api/v1/keys). Stored at <dataDir>/keys/prod.keys with mode 0600. The API reports which names are present; key material is never returned, logged, or sent to a device.

Without keys the library still lists files from containers, tickets, and filenames, and labels that metadata as unverified. Details: docs/keys.md.

Documentation

  • Architecture — how the pieces fit together, and why
  • Deploy — Docker image, Coolify, volumes
  • Device API — pairing, catalog, jobs, Range downloads
  • USB protocol — frame layout (same messages as HTTP)
  • Keysprod.keys and filename mode
  • Switch updates — one channel of signed .nro releases, fetched from GitHub or mirrored on your server

Contributing

Issues and pull requests are welcome — start with CONTRIBUTING.md, which covers setup, house style, and the things this project will not accept. Security vulnerabilities go through SECURITY.md rather than the issue tracker.

Licence

Apache License 2.0. Third-party components, including Borealis, TweetNaCl, libnx, the devkitPro portlibs, and the bundled Archivo font, are listed in THIRD-PARTY.md.

NSLibrary is an independent, unofficial project. It is not affiliated with, endorsed by, or associated with Nintendo. Nintendo Switch is a trademark of Nintendo. All product names, logos, and brands are the property of their respective owners, and are used only to describe what this software interoperates with.

NSLibrary is a file manager and a transfer tool. It ships no games, no keys, no firmware, and no copyrighted Nintendo material of any kind; every test fixture in this repository is synthetic and generated from scratch. It provides no way to obtain content, and does not circumvent any protection measure — prod.keys must already be extracted from a console you own, and is optional.

What you do with it is your responsibility. Dumping content you own is treated differently in different countries; downloading or sharing content you do not own is not something this project supports, and running modified system software may violate Nintendo's terms of service and can get a console banned from online services.

Contributors

tuckerwales

2 commits

Languages

TypeScript

57.2%

C++

35.7%

C

3.2%

JavaScript

1.9%