custom-install: putting a 3DS title straight onto an SD card
Installs a title directly to an SD card for the Nintendo 3DS
At a glance
- What is it?
- custom-install is a Python tool that installs a title file directly to a Nintendo 3DS SD card instead of going through the system's own installer flow, with a GUI for Windows and a command line mode everywhere else. It needs console dumps, a SeedDB for newer titles, and a separate finalize homebrew to make the installed title appear.
- Who is it for?
- custom-install suits a 3DS owner who wants titles installed to the SD card in a repeatable, scriptable way and who is comfortable reading a seed database and a manual dump procedure. Skip it if you only want to install a homebrew application once, since the system installer already covers that, and skip it if you are unwilling to dump console keys, because movable.sed and boot9.bin are not optional.
- 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 141 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the tool actually does to the SD card
The repository describes itself in one line: it installs a title directly to an SD card for the Nintendo 3DS, and it was originally created in late June 2019. The distinction the project is built around is where the install happens. The console's own flow copies a title into internal storage through its system menu, which is a per title, per session process with a fixed interface. custom-install writes the title into the SD card layout directly, so a title can be placed on the card by a script, from a command line, over a network share, or from a build pipeline, and the same procedure can be repeated for many titles at once. The title files it consumes are the.cia format, and the README's usage examples take a list of them as trailing arguments. The project is MIT licensed, written in Python, and it also exists as a homebrew side project for the device itself, which is where the finalize piece comes in.
Two ways in: a Windows standalone build or pip
The README documents two routes. For Windows without Python, you dump the system files, download the latest releases, extract and run ci-gui, then read windows-quickstart.txt. For the Python route, and for macOS and Linux, you install the package from the repository archive. On Windows the py launcher is enough, and the README makes a point of saying that adding Python to PATH is not required because Python installs with the py launcher by default. The install commands differ only in the interpreter prefix:
python3 -m pip install --user --upgrade https://github.com/ihaveamac/custom-install/archive/refs/heads/python-package.zipOn Windows the same line is run with py -3 -m pip. After installation, the GUI is started with the custominstall.gui module and the command line version with the custominstall module, again with py -3 on Windows and python3 elsewhere. The pyproject.toml also registers console entry points, custominstall and custominstall-gui, and declares the package data that ships inside the wheel, including prebuilt save3ds_fuse binaries for Darwin and win32, the title database and the custom-install-finalize homebrew payload.
The three inputs and where the tool looks for them
The setup section is the part that decides whether a run succeeds. movable.sed is required and can be supplied with -m or --movable. boot9 is needed and is looked for in a fixed order: the -b or --boot9 argument, then the BOOT9_PATH environment variable, then %APPDATA%\3ds\boot9.bin on Windows, ~/Library/Application Support/3ds/boot9.bin on macOS, then ~/.3ds/boot9.bin and ~/3ds/boot9.bin. A SeedDB is needed for newer games from 2015 onward that use seeds, and it is searched in the same style: -s or --seeddb, then SEEDDB_PATH, then the platform specific application directories and the two home directories. Both boot9.bin and movable.sed come from dumping a 3DS system, and the README links two different write ups of that procedure depending on which route you took. The search order is worth internalising, because it means a stale file in one of those directories silently wins over the argument you just typed only in the sense that the argument wins, and a leftover in the wrong place will confuse you later.
custom-install-finalize is the step that makes the title appear
Installing the files is only half of the job. The README states that custom-install-finalize installs a ticket, plus a seed if required, and that this is required for the title to appear and function. In other words, the title data on the SD card is inert until the finalize homebrew runs and the console is told the title is installed and trusted. That homebrew lives in the finalize/ directory of the repository and is built the way most 3DS homebrew projects are built, with devkitARM, which the README links. The Python package carries custom-install-finalize.3dsx as package data, so the payload ships inside the wheel and the whole process can be driven from a computer. The division of labour is the design point worth noting: the heavy lifting on the console is a small compiled homebrew, while the orchestration, the title database work and the user interface are Python on the host machine.
Command line usage and the two front ends
The command line form takes the dumps, the target card and the titles. The README gives one example per platform, differing only in the path of the mounted card:
py -3 -m custominstall -b boot9.bin -m movable.sed --sd E:\ file.cia file2.ciapython3 -m custominstall -b boot9.bin -m movable.sed --sd /Volumes/GM9SD file.cia file2.ciaThe --sd option points at the card, which on macOS appears as a volume and on Linux as a mount point. Use -h to view the full argument list, which the README states rather than reproduces. The GUI exists to make the process easier, and it is a separate entry point rather than a flag. On Linux it needs a Tk package, and the README lists the three distribution specific commands: sudo apt install python3-tk on Ubuntu and Debian, sudo pacman -S tk on Arch, and sudo dnf install python3-tkinter on Fedora. The GUI was redesigned twice, with credit given to the two designers in the credits section.
The save3ds dependency and what Linux users must build
The one dependency that is not a Python package is save3ds by wwylele, used to interact with the Title Database, which the credits section explains in the bin/README. macOS and Windows users get a prebuilt save3ds_fuse binary shipped inside the package data. Linux users must build wwylele/save3ds themselves and place the save3ds_fuse binary in one of three places: a directory in PATH, in custominstall/bin/linux, or at the path given by the CUSTOM_INSTALL_SAVE3DS_PATH environment variable. That is a real difference between platforms, and it means the Linux instructions are not a one liner. The Python dependency list is otherwise short: pyctr for the title cryptography work, events for the application event loop behind the GUI, and comtypes on Windows only, selected by an environment marker for os_name == 'nt'.
Licence, release history and an outdated section to ignore
The licence is MIT, declared both in the LICENSE.md file at the root and in the pyproject.toml metadata, and the project requires Python 3.8 or newer with classifiers running up to 3.14. On releases the picture is mixed. The recent tags are v2.1 from 2021-09-12, v2.1b4 from 2021-07-08 and v2.1b3 from 2021-03-09, each of them covering a custom-install and finalize version pair. The last push was on 2026-06-05, so the tree is still being touched even though the tagged releases are from 2021, and the repository ships a flake.nix and package.nix for Nix users. One section of the README should be ignored on purpose. The Building Windows standalone section carries a warning that it is outdated and does not currently work with the Python package setup, so treat the pip route as the supported path. The default branch is python-package rather than main, which is a hint that the package layout is the current form of the project.
Editorial conclusion
custom-install suits a 3DS owner who wants titles installed to the SD card in a repeatable, scriptable way and who is comfortable reading a seed database and a manual dump procedure. Skip it if you only want to install a homebrew application once, since the system installer already covers that, and skip it if you are unwilling to dump console keys, because movable.sed and boot9.bin are not optional. Before running it, read the wiki pages the README links for dumping system files, check that your region and title set are covered by the SeedDB, and note that decrypting your own backups still depends on the copyright law and the title's licence terms where you live.
Frequently asked questions
How do I install custom-install for the Nintendo 3DS?
On macOS and Linux run python3 -m pip install --user --upgrade with the URL of the python-package.zip archive from the repository, and on Windows use the py launcher in the same way. The GUI is then started with python3 -m custominstall.gui or py -3 -m custominstall.gui.
What files does custom-install need before it will run?
movable.sed is required and is passed with -m or --movable, boot9 is needed and is found through -b, the BOOT9_PATH environment variable or the platform application directories, and a SeedDB is needed for 2015 and later titles that use seeds, searched through -s, SEEDDB_PATH and the same directory list.
What is custom-install-finalize for?
It installs a ticket, plus a seed if required, and the README states it is required for the title to appear and function. It is a small homebrew built with devkitARM and shipped inside the Python package as custom-install-finalize.3dsx.
What do Linux users need to do that other platforms do not?
Linux users must build wwylele/save3ds and place save3ds_fuse in a directory in PATH, in custominstall/bin/linux, or at the location given by the CUSTOM_INSTALL_SAVE3DS_PATH environment variable. They may also need a Tk package, such as python3-tk on Ubuntu and Debian, tk on Arch or python3-tkinter on Fedora, for the GUI.
How do I install a title to the SD card with custom-install?
Use the command line form with the dumps, the card path and the title files, for example py -3 -m custominstall -b boot9.bin -m movable.sed --sd E:\ file.cia file2.cia on Windows. The README gives the same form with a volume path on macOS and a mount point on Linux, and -h shows the full argument list.
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-custom-install)Was this useful?