ninfs: mounting your own Nintendo console dumps as a filesystem
FUSE filesystem Python scripts for Nintendo console files
At a glance
- What is it?
- ninfs is a MIT-licensed Python and FUSE program that presents the contents of Nintendo 3DS, DS, iQue and Switch images as a browsable virtual filesystem, so you can copy files out of a cart, a NAND backup or an SD card without unpacking the containers first. It suits someone who works with their own console dumps, and it needs Python 3.12 plus a FUSE driver on each platform.
- Who is it for?
- ninfs is worth installing if you want to get at the contents of console images you already have, because the whole point of a FUSE presentation is that every tool that reads a directory works on it, so a container format you would otherwise have to unpack with a separate tool becomes something you can browse with a file manager and copy files out of. It is the wrong tool if you do not have the images, and the wrong tool for a console whose encryption keys you cannot obtain.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 49 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The idea: a container format you browse like a folder
ninfs, formerly fuse-3ds, is a FUSE program to extract data from Nintendo game consoles. It works by presenting a virtual filesystem with the contents of your games, your NAND, or your SD card contents, and you can browse and copy out just the files that you need.
That framing is the whole design, and it is a better idea than it first sounds. Nintendo's formats are nested: a cart image contains partitions, a partition contains an NCCH, an NCCH contains a RomFS, and RomFS contains files. The usual way to get a file out is to run a series of unpacking tools, one per layer, and to know the layout before you start. With a FUSE mount, the layers are the mount's problem and the file system is the result, so a directory listing, a file copy and a checksum all work the way they would on any other disk image.
The example uses spell out the practical consequences. You can mount a NAND backup and browse CTRNAND, TWLNAND and others, and write back to them without having to extract and decrypt them first. You can browse decrypted SD card contents, dump installed games and saves, or copy contents between two systems' SD contents. And you can extract a game's files out of a CIA, a CCI, an NCCH or RomFS, or raw CDN contents, just by mounting them and browsing, and the documentation goes one step further and notes you can use the virtual decrypted file and start playing the game in a 3DS emulator right away.
The tool is written in Python, is MIT licensed, and the primary language is Python. The author is Ian Burgwin, and the recent releases are v2.0 from 2024-02-25, v2.0a11 from 2024-01-30 and v2.0a10 from 2023-08-07, with the last push to the repository on 2026-09-05.
What it can mount, and the formats that are read-only
The supported type list is long and specific, and it is the best guide to what the tool actually handles.
For Nintendo 3DS there is the CTR cart image with the .3ds and .cci extensions, CDN contents in the form of cetk, tmd and the contents themselves, the CTR Importable Archive with the .cia extension, the Executable Filesystem as .exefs and exefs.bin, the Nintendo 3DS NAND backup as nand.bin, NCCH with the .cxi, .cfa, .ncch and .app extensions, the Read-only Filesystem as .romfs and romfs.bin, SD Card Contents read from an SD card, Installed SD Title Contents from the tmd and app files, and 3DSX Homebrew with the .3dsx extension.
For Nintendo DS and DSi there is the DSi NAND backup as nand_dsi.bin and the Nintendo DS ROM image with the .nds and .srl extensions. The iQue Player contributes a NAND backup that is read-only. The Nintendo Switch contributes a NAND backup as rawnand.bin.
Two things stand out. The Switch support is a NAND backup only, so the tool is about the console's internal storage rather than about Switch game images, and the iQue backup is explicitly read-only, so the write-back path that the 3DS NAND has is not universal.
The format list is also a map of the history of the hardware. The 3DS formats are numerous because the 3DS had several layers of packaging, and the Switch entry being a single item tells you how much less the project is trying to do for that console.
The key material, and the order the tool looks for it in
Getting the tool to mount a 3DS image needs key material, and the documentation is unusually precise about where it looks and in what order.
For 3DS types the ARM9 BootROM is required, and you can dump it using boot9strap, which is set up through the 3DS Hacks Guide, with the steps to dump Boot9 on the wiki. The search order for the file is a --boot9 command line argument if set, then the BOOT9_PATH environment variable if set, then %APPDATA%\3ds\boot9.bin on Windows, then ~/Library/Application Support/3ds/boot9.bin on macOS, then ~/.3ds/boot9.bin, and finally ~/3ds/boot9.bin. For historical reasons boot9_prot.bin can be used in all of those locations as well, and the documentation explains that the tilde means the user's home directory, so ~/3ds would be the /Users/username/3ds directory on macOS and C:\Users\username\3ds on Windows.
The SeedDB has a parallel structure. CDN, CIA and NCCH mounting may need SeedDB for mounting NCCH containers of newer games, those from 2015 onwards, that use seeds. The lookup order is a --seeddb argument, the SEEDDB_PATH environment variable, %APPDATA%\3ds\seeddb.bin on Windows, ~/Library/Application Support/3ds/seeddb.bin on macOS, ~/.3ds/seeddb.bin and ~/3ds/seeddb.bin.
The two lists are the same shape for a reason. The tool is designed to be run by someone who has just extracted a dump and wants to look at it, so the key material is looked for in the places a person would naturally put it, with the command line and the environment variable taking priority for a scripted workflow.
It is worth being explicit that all of this key material comes from the user's own console. The BootROM is dumped from the hardware with boot9strap, and the seed database is a lookup table. That is the line that separates a data access tool from a circumvention tool, and it is the line ninfs stays on.
Python 3.12 or later is required, and the packaging metadata confirms it with a requires-python of 3.12 or newer and classifiers for Python 3.12 through 3.15.
Installing on each platform, and the driver differences that decide your afternoon
The installation instructions are per platform, and the differences are about the FUSE driver rather than about Python.
On Windows, 10 or 11 is recommended, 8.1 is the minimum but untested, and 7 or earlier are unsupported. An installer is provided in the releases, and it includes both ninfs and WinFsp, which is installed if required. A standalone zip is also provided, and WinFsp must be installed separately. With an existing Python, the route is to install Python 3.12 or later, preferring the x86-64 version on 64-bit Windows, and the documentation warns that the Python from the Microsoft Store is not recommended due to sandboxing restrictions. The install command is:
py -3 -m pip install --upgrade https://github.com/ihaveamac/ninfs/archive/2.0.zipWindows on ARM is handled honestly. Official support will come eventually, per an open issue, and in the meantime the x86 version has been tested and seems to work properly, with the advice to install the latest WinFsp version with ARM64 support.
On macOS, versions of macOS supported by Apple are highly recommended and macOS 12 Monterey is the oldest that should work, and macFUSE or fuse-t is required. A standalone build is provided in the releases, built for Intel and Apple Silicon and signed and notarized by Apple, though macFUSE or fuse-t must still be installed separately. The install-with-Python route lists several ways to get Python, from the python.org installers through Xcode or the Command Line Tools, Homebrew, MacPorts and Nix, and then:
python3 -m pip install --upgrade https://github.com/ihaveamac/ninfs/archive/2.0.zipOn Linux there is an AUR package for Arch, in normal, gui, git and git-with-gui variants, and for other distributions the note is that recent ones such as Ubuntu 24.04 and later should have Python 3.12 or later pre-installed, and that most distributions have libfuse enabled by default. The install command is:
python3 -m pip install --upgrade --user https://github.com/ihaveamac/ninfs/archive/2.0.zipwith the note that --user is not needed inside a virtual environment. There is also a desktop entry command, python3 -m ninfs --install-desktop-entry, with an optional second argument for a location other than the default under $XDG_DATA_HOME, and the GUI needs tkinter, which is python3-tk on Debian and Ubuntu systems and python3-tkinter on Fedora.
For Nix there is a derivation, tested on NixOS, other Linux distributions and macOS, with the note that macFUSE or fuse-t must be installed separately because nixpkgs does not, and probably cannot, package either. With flakes the two commands are:
nix run github:ihaveamac/ninfs
nix run github:ihaveamac/ninfs -- cia game.cia mountpointEverything else is untested and may not work properly, and there is a specific known failure: ninfs is known not to work on FreeBSD, with an issue link.
How the package is put together, and the command surface it exposes
The packaging metadata shows a small dependency set with a specific division of labour.
dependencies = [
"pyctr>=0.7.6,<0.9",
"haccrypto>=0.1",
"pycryptodomex>=3.9,<4",
"pypng>=0.0.21",
"setuptools>=61.0.0",
"mfusepy~=1.0",
"packaging>=26"
]The cryptography is split across three packages, which is not accidental. The dependency list does not explain what each package does, but the split across three crypto-related packages is easy to see from the names and version pins alone. mfusepy is the FUSE binding, and pyctr is the library the 3DS formats are built on. The upper bound on pyctr, below 0.9, is a deliberate constraint rather than an accident of a lock file, and it is the kind of pin that tells you the project is sensitive to upstream changes in that library.
The command surface is unusually wide, and the reason is that the mount type has to be selected. The scripts section defines one entry point per format, with mount_3ds, mount_3dsx, mount_app, mount_cci, mount_cdn, mount_cfa, mount_cia, mount_csu, mount_cxi, mount_exefs, mount_nand, mount_nandbb, mount_nandctr, mount_nanddsi, mount_nandhac, mount_nandique, mount_nandnx, mount_nandswitch, mount_nandtwl, mount_ncch, mount_nds, mount_romfs, mount_sd, mount_sdtitle, mount_srl and mount_threedsx, all pointing at the same ninfs.main:main entry, plus a plain ninfs command and a ninfsw GUI script that also points at ninfs.main:gui.
So the same program is exposed under a different name for each format, and each name selects the right container parser. That is a design decision about discoverability: a user with a.cia file runs mount_cia, and the argument list is empty, rather than passing a format flag to a generic command.
The rest of the tree supports the packaging story. There is a setup.py that is a thin shim over setuptools, a setup-cxfreeze.py for the frozen Windows build, a standalone.spec for the PyInstaller build, a wininstbuild/ directory for the Windows installer, a nix/ directory, a templates/ directory, a resources/ directory, and the documentation set of BUILDING.md, DEVELOPMENT.md and CONTRIBUTING.md. The version is dynamic in the packaging metadata, so it comes from the source tree rather than being written in two places.
Editorial conclusion
ninfs is worth installing if you want to get at the contents of console images you already have, because the whole point of a FUSE presentation is that every tool that reads a directory works on it, so a container format you would otherwise have to unpack with a separate tool becomes something you can browse with a file manager and copy files out of. It is the wrong tool if you do not have the images, and the wrong tool for a console whose encryption keys you cannot obtain. Before you start, check three things: that you can supply the key material the format needs, since for 3DS types the ARM9 BootROM is required and has to be dumped from your own console with boot9strap following the 3DS Hacks Guide, and CDN, CIA and NCCH mounting may need SeedDB for 2015 and later titles that use seeds; that you have the right FUSE driver, since Windows needs WinFsp, macOS needs macFUSE or fuse-t, and Linux needs libfuse, and the Windows installer bundles WinFsp while the standalone zip does not; and that your Python is 3.12 or newer, since that is the stated requirement, and that on Windows the Microsoft Store build of Python is not recommended because of its sandboxing restrictions.
Frequently asked questions
What does ninfs let me do with my Nintendo console files?
It presents your games, NAND backups and SD card contents as a virtual filesystem, so you can browse and copy out individual files without unpacking the nested containers by hand. You can mount a NAND backup and write back to it, dump installed games and saves, copy contents between two systems' SD contents, and mount a CIA, CCI, NCCH, RomFS or raw CDN contents as a directory.
What do I need before ninfs can mount a 3DS image?
The ARM9 BootROM, which you dump from your own console with boot9strap following the 3DS Hacks Guide, and ninfs looks for boot9.bin in a --boot9 argument, the BOOT9_PATH environment variable, %APPDATA%\3ds\boot9.bin on Windows, ~/Library/Application Support/3ds/boot9.bin on macOS, ~/.3ds/boot9.bin or ~/3ds/boot9.bin, and boot9_prot.bin works in those places too. CDN, CIA and NCCH mounting of 2015 and later titles that use seeds may also need SeedDB.
How do I install ninfs on Windows, macOS and Linux?
Python 3.12 or later is required everywhere, and the FUSE driver differs: Windows needs WinFsp, included in the installer but separate for the standalone zip, macOS needs macFUSE or fuse-t, and Linux needs libfuse. The install command is pip install of the release archive, the AUR carries Arch packages, and Nix users can run the flake directly with nix run github:ihaveamac/ninfs, with macFUSE or fuse-t still installed separately.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ihaveamac-ninfs)Was this useful?