NanoTorrent

NanoTorrentA tiny, hackable
BitTorrent client

NanoTorrent is a pure-Rust port of PicoTorrent — the same lean application, rebuilt without a single C++ dependency, now on Windows, macOS and Linux. One Slint window everywhere, dark mode, a built-in web remote, and it reads your existing PicoTorrent settings on first run.

Written in Rust 2024 Windows · macOS · Linux Slint UI Dark mode DHT · PeX · MSE/PE uTP · LSD · web seeds BitTorrent v1 · v2 · hybrid Built-in web remote Headless mode Rhai plugins Strict network mode 41 languages

Windows installer Microsoft Store macOS disk image Debian / Ubuntu .deb Fedora / RHEL .rpm Linux AppImage

Windows 10 / 11 · macOS · Linux

A look inside

One window, three platforms

The desktop client is drawn by Slint, so Windows, macOS and Linux get the same window rather than three approximations of it — and the web interface it ships with follows the same theme and the same language.

The NanoTorrent main window in its dark theme
The main window. The torrent list with all 16 columns and a rendered progress bar, the icon toolbar above it, and the details panel below. Everything here is drawn by Slint, so it is the same window on Windows, macOS and Linux.
The main window in its light theme
Light theme. Follows the OS by default, or is pinned in Preferences. The toolbar glyphs are drawn rather than shipped as images, so one set works on both palettes.
The Files tab of the details panel
Details ▸ Files. Per-file size, progress and an include toggle, as a tree for multi-file torrents. Peers — with GeoIP country and flag — and Trackers sit beside it.
The Preferences dialog
Preferences. Six tabs, applied live on OK: the session is rebuilt rather than requiring a restart, so rate limits, DHT, PeX, encryption and the proxy take effect at once.
The built-in web interface in its dark theme
The web interface. An authenticated HTTPS remote that ships in the binary: add, watch, pause, resume, recheck, remove, move and set a location, from any browser on the network.
The web interface in its light theme
It follows the theme too, and renders in the configured language — substituted server-side, so there is no flash of English and no second request.
The web interface Preferences drawer
The same settings, remotely. The drawer behind the hamburger is generated from the command line’s settings registry, so the desktop dialog, the terminal and the browser share one list, one set of types and one validator.

The torrents shown are Linux distribution images, used as sample data.

New in 0.3.3

What’s new

0.3.3 is about not leaking, and about the web interface catching up with the window. Just before it, 0.3.2 gave plugins a network, a store and a window of their own — the RSS reader that ships with it is built out of exactly those.

Strict network mode Binding to a VPN interface or pointing at a SOCKS proxy has always been a preference: the parts that cannot honour it carry on regardless, and on a torrent client those are the loudest ones. DHT and uTP are UDP with no proxy code, local discovery is LAN multicast, UPnP talks to the router. Strict mode switches off whatever the chosen protection cannot cover, refuses to start if the named interface is missing, and pauses every torrent if it disappears while running. The status bar shows the proxy and the binding, and turns red when the interface has gone.
Interface binding works on Windows librqbit implements it as SO_BINDTODEVICE, which Windows does not have, so the whole feature was Linux and macOS only — a Windows user who set one got “binding to device is not supported on your OS” and an app that would not start. Windows now binds the interface’s address instead, which the strong host model makes a real restriction rather than a hint.
A path-escape fix A malicious .torrent could write outside the download folder on Windows. The traversal check everyone tests for rejects .. and separators, and it does — what it does not reject is a drive prefix, and PathBuf::push throws the whole buffer away when the pushed path carries one. A file named C:evil.txt passed validation and landed relative to the current directory of drive C. Any relative path whose components are not all plain names is now refused at the storage layer, so it covers magnets too.
The web interface grew a toolbar It was a list with an add button. It now has the desktop’s toolbar — add magnet, add torrent, remove, resume, pause — with multi-select by ctrl- and shift-click, the same speed charts as the window, columns you can resize whose widths are stored server-side rather than in one browser, and drag-and-drop to add. Adding several at once already worked; now it is findable.
Plugins reach the browser A plugin’s window is state held by the plugin host rather than by the desktop window, so the browser renders the same surface from the same data: a .rhai plugin written for the desktop appears in the web interface unchanged and needs no extra permission. The browser can list plugins and switch them on and off, but deliberately cannot approve one — consent to what a script may reach is given at the machine it runs on. The whole plugin API is written up in the developer reference.
A brute-force lockout, and dialogs that fit How many failed logins, over what window, and how long that address is then refused — five in sixty seconds, then an hour, by default. It counts per address, so nobody can lock the owner out by hammering it, and the window and the block are separate settings, because one number for both forces a choice between a long lockout and a long memory for stray typos. Fixed alongside it: dialogs could open taller than the screen with no scrollbar, because the clamp measured the window before it existed.
What you get

Everything the original did — and then some

The full PicoTorrent feature set, ported across: settings database, translations, layout and all. Plus two things it never had — three platforms, and a web interface.

Windows, macOS and Linux

The front end was rebuilt on Slint, so it is one window and one codebase on all three. Ships as an .exe installer, a .dmg, .deb and .rpm packages, and an AppImage that needs no install at all — or install it from the Microsoft Store.

Built-in web interface

An Actix server over HTTPS — self-signed by default, Argon2id password hashing, a configurable per-address lockout that answers repeated failed logins with a 429, and it flatly refuses to listen off-loopback in plaintext. It carries the desktop’s toolbar and speed charts, multi-select, drag-and-drop adding, resizable columns whose widths are stored server-side, plus a Preferences drawer holding every setting the desktop dialog has, in the configured language.

Headless mode

Build with --no-default-features for no window at all — a seedbox daemon driven entirely through the web interface. And every preference the dialog offers is settable without one: --list-settings prints them all with their ranges, --get reads one, --set changes one.

Plugins, on a leash

Optional Rhai scripts react to session events and to a once-a-minute tick, and drive the session back through the web API’s own verbs. Ten permissions — including network for a capped http_get, data for a store of their own and ui for a window, a menu and a cog in Preferences. Each is declared in a one-line header read before the script runs, and the plugin gets an engine holding only that, so reaching past the grant fails with “function not found”. Off by default; a working RSS reader ships as an example, and shows up in the web interface too. Write one ▸

Live settings

DHT with a persisted routing table, UDP trackers, rate limits, SOCKS proxy with per-scope toggles, fast resume. Preferences ▸ OK rebuilds the session — no restart.

Strict network mode

Stop rather than leak. Turned on, it switches off whatever your VPN interface or SOCKS proxy cannot cover — DHT, uTP, local discovery, UPnP — refuses to start if the named interface is not there, and pauses every torrent if it vanishes while running. Interface binding works on Windows now too. It is not a firewall: it stops this client talking around the tunnel, nothing else on the machine.

Live speed charts

Two of them in the toolbar, one per direction, each holding the last minute and riding the list’s own refresh tick rather than a timer of its own. Each scales to its own peak instead of a shared one, so upload is not flattened into a line along the bottom, and each states that peak in its tooltip. The web interface has the same pair.

MSE / PE encryption

Protocol encryption on both incoming and outgoing connections, RC4, with require-encryption toggles. Anonymous mode randomises the peer id.

The full torrent list

All 16 columns with a rendered progress bar, click-to-sort, multi-select, and the complete context menu: recheck, move storage, labels, copy magnet, open in Explorer.

Details that matter

Overview with a piece-availability bar, per-file include toggles, peers with GeoIP country and flag, and trackers grouped into announce tiers.

Smart magnet adds

Magnet links fetch their metadata first, then show you the real file list in the same dialog you get for a .torrent — pick your files before it starts.

BitTorrent v2, not just the checkbox

v2-only .torrent files and v2-only magnets both download and seed, verified against their merkle piece hashes. No librqbit release implements BEP 52, so it is written here: the piece layers a magnet cannot carry are fetched with the v2 hash messages and checked against each file’s pieces root before a single byte of content is asked for. Hybrids announce under both info hashes at once.

Web seeds

A url-list seed (BEP 19) becomes a synthetic peer fed by HTTP range requests, so its pieces are hash-checked exactly like a real peer’s and a stale mirror is discarded rather than trusted. One request per piece rather than per 16 KiB chunk, and a failed fetch retries instead of killing the seed.

uTP and local discovery

µTP (BEP 29) adds a UDP transport worth having where TCP is throttled — off by default, since it opens a second socket on the same port. Local service discovery (BEP 14) finds peers on your own network without a tracker or the DHT, and is on.

Torrent creation

Create BitTorrent v1, v2 or hybrid torrents (BEP 52) with trackers, comment and the private flag.

Native notifications

Windows 11 WinRT toasts on completion under a registered AppUserModelID, plus a tray icon that reports your transfer rates on hover. In-app toasts cover everything else on every platform — a failed add is red, not the same blue as “Copied to clipboard”.

Filters & labels

The PQL query subset — status = "downloading" and dl > 1kbps — with an optional console, plus coloured labels, save paths and auto-apply.

GeoIP & IP filtering

DB-IP country lookup for peers, and eMule / PeerGuardian blocklist support.

Bring your setup along

On Windows, first run copies your existing %LOCALAPPDATA%\PicoTorrent folder — settings and session state — leaving the original untouched. Torrents import in one shot.

Every translation

All 41 languages, complete — every string the UI can show, and a translated --help to go with it. Compiled into the executable, listed by their native names, and switchable live without a restart.

Lists that remember

An icon toolbar above the list, and columns you can drag, double-click to fit, or reset from a right-click. Widths are remembered per list — the torrent list and all three details tabs — along with the panel height and its divider.

Move storage & set location

Move relocates the files; Set location relocates the torrent, for data you moved by hand or restored from a backup. An intact copy verifies straight back to complete, and pointing it somewhere empty warns rather than quietly starting an 18 GB re-download.

Low-disk guard

Pause everything when free space on the save path drops below a percentage of the volume. librqbit has no such mechanism, so it is checked here every 30 seconds. Off by default; 5% when enabled.

The BEPs, spelled out

Seventeen of them, fifteen in full: DHT, metadata exchange, the extension protocol, PeX, multitracker tiers, UDP trackers, the fast extension’s five messages, upload_only, padding files, compact peer lists and private torrents. The README carries the whole table, checked against the vendored engine rather than against the settings database.

One file, no baggage

Languages and 252 country flags are embedded at build time, and so is the web interface. The binary ships standalone — nothing needs to travel next to it.

Under the hood

Same app, different foundations

The C++ / libtorrent / wxWidgets stack swapped out for pure-Rust building blocks — while keeping the original's structure, settings schema and behaviour.

Aspect PicoTorrent (C++) NanoTorrent (Rust)
PlatformsWindowsWindows, macOS, Linux — plus a headless build
BitTorrent engineRasterbar-libtorrentlibrqbit 9.0.1 (vendored + patched)
GUIwxWidgets (native Win32)Slint — one window on all three, with dark mode
Remote controlBuilt-in Actix web interface over HTTPS, with the desktop’s toolbar and charts
Settings storageSQLite (PicoTorrent.sqlite)Same schema (NanoTorrent.sqlite)
Resume datalibtorrent resume blobs in DBlibrqbit session persistence (JSON + .bitv mmap)
Translationslang/*.json embedded in a DBSame files compiled into the exe — 41 languages, switchable live
Single instance / IPCWin32 mutex + WM_COPYDATALoopback TCP on port 37549
NotificationsTray balloonsNative desktop notifications on all three platforms, plus in-app toasts
Loggingboost::log to filetracing to file
PackagingNSIS installer.exe · .dmg · .deb · .rpm · AppImage · Microsoft Store
Command lineTorrent and magnet argumentsEvery preference settable — and --help in all 41 languages
ExtensibilityRhai plugins with ten declared, enforced permissions — network, storage and a window of their own
Leak protectionStrict network mode — stops rather than leaks, and pauses if the interface goes
Build requirementsMSVC + C++ dependency treeRust 1.85+ · cargo build --release
Standing on shoulders

Built on PicoTorrent

NanoTorrent is a port, not a rewrite from scratch. It owes its application structure, its settings database schema, its dialogs and its whole design philosophy to PicoTorrent — the excellent, deliberately small Windows BitTorrent client by Viktor Elofsson and contributors.

PicoTorrent is still available and still worth your time. If you're happy with it, keep using it — NanoTorrent exists for people who want the same experience on a memory-safe, C++-free stack.

This port is built predominantly with AI assistance under human review — see the AI declaration.

Visit PicoTorrent
PicoTorrentC++ · wxWidgets
libtorrent
NanoTorrentRust 2024 · Slint
librqbit
Straight with you

Where the edges still are

Most of what used to be listed here is done. This is what is left, and what changes when it runs packaged from the Store.

v2 seeding is only half done Reading is finished — v2-only torrents and v2-only magnets both download and seed, and a hybrid announces in both swarms. The other direction is not: NanoTorrent does not answer an incoming hash request, so it cannot bootstrap someone else’s v2 magnet, and it does not set the v2 handshake bit, because advertising support it cannot honour would be worse than staying quiet.
Web seeds are peers, not a second pipe A url-list seed is served as a synthetic peer, so its pieces are hash-checked and a wrong one is discarded the way a bad peer is — but a server that ignores Range and answers 200 with the whole file is refused rather than downloaded. Neither FTP nor BEP 17 httpseeds is spoken.
Peer counts have no source librqbit does not record which mechanism found a peer, so the DHT, LSD and PeX rows in the Trackers tab are status-only. A hybrid’s announce numbers are its v1 swarm’s; the second announce happens and finds peers, it is just not counted there.
Linux notifications need a daemon Windows and macOS always have somewhere to put a desktop notification; on Linux it goes to the D-Bus notification daemon, so a session without one — a headless box, a bare window manager — logs a warning and shows nothing. Its icon is looked up by the name the .desktop entry uses, so an install that never ran the desktop-entry script gets the generic glyph.
The Store build lives in a container Windows redirects the app’s data folder into the package’s own store, so a Store install does not see an installer install’s settings and the one-time PicoTorrent import looks in the redirected path. The “set as default” button is redundant there as well — the manifest declares the file and magnet associations itself.
macOS asks about your local network Local service discovery is on by default and sends multicast, so macOS raises its Local Network Privacy prompt on first launch. The bundle carries a reason string so the dialog says why; declining switches LSD off and nothing else.
Strict mode is not a firewall It stops NanoTorrent from talking around your tunnel by switching off what the tunnel cannot cover. It cannot stop anything else on the machine, and it cannot prove the proxy is where it claims to be. On Windows the interface binding is IPv4-only, since it binds an address and one socket carries one.
The translations are machine-assisted English is the only locale written by hand. The other 40 are complete rather than reviewed, so the failure mode is a wrong word in a language none of us reads. Corrections are welcome, and a lang/ folder next to the executable overrides a locale without a rebuild.
Magnet protocol default Windows blocks force-setting the magnet handler when another client claimed it. NanoTorrent registers itself and opens Settings ▸ Default apps so you can confirm.

Give it a spin

Windows, macOS or Linux — an installer or a package each, plus an AppImage that needs neither and a Microsoft Store listing that keeps itself up to date. Your PicoTorrent setup comes with you, and the Discord is there if you get stuck.