Downloads
How downloads work
Downloads stream directly from disk with no temp file, no copy, and no packaging delay, so large ROMs and multi-disc sets download just as quickly as small ones.
For multi-file games (folder-based), the bundled nginx is built with mod_zip, which streams a zip archive over HTTP without ever materialising it on disk. The browser sees a zip download start immediately with no "packaging…" step, regardless of the folder size.
Auth
Download URLs require either a session cookie or a bearer token by default. Two patterns for programmatic/third-party use:
Client API tokens (preferred)
Issue a Client API Token and pass it as a bearer:
curl -H "Authorization: Bearer rmm_..." \
-o mario.sfc \
https://demo.romm.app/api/roms/123/content/mario.sfc
Disabling auth on download endpoints
Some third-party tools (like a dumb emulator loading a ROM by URL or a homebrew Switch app) can't send a bearer token. For those, admins can disable auth on download endpoints:
This makes ROM and firmware download URLs work unauthenticated.
Only enable this behind upstream auth
This flag makes your library world-downloadable from whatever URL serves it. Only set it when you have authentication at the reverse-proxy layer (Authelia, Cloudflare Access, an IP allowlist, or a VPN).
Nintendo 3DS direct install
The 3DS built-in QR scanner can install compatible .cia files directly from a URL. RomM produces compatible QR codes, so a 3DS with FBI (or another CIA installer) can install over the air given network access to your instance and either basic-auth on the 3DS side or DISABLE_DOWNLOAD_ENDPOINT_AUTH=true behind upstream auth.
Streaming to an emulator
Some emulators take an HTTP URL directly. With DISABLE_DOWNLOAD_ENDPOINT_AUTH=true and a reverse proxy that restricts access, you can set up truly remote ROM loading from a handheld over Wi-Fi.
Troubleshooting
- Download stalls at N%: usually the reverse proxy buffering to disk (see Reverse Proxy → Nginx Proxy Manager for the
proxy_max_temp_file_size 0fix). - Multi-file zip download is corrupt: disk may have filled up during streaming, or the nginx mod_zip build is broken. Check
docker logs romm | grep mod_zip.