Benchmarks

Five clients, eight scenarios, identical hardware and providers, runs interleaved so provider drift cancels. The metric is time to a usable file: downloaded, verified, extracted. Includes the legs we don't win.

On this page

Methodology first

The setup

Scenario 1 · clean, huge

190.6 GB → single 167.9 GB mkv (Europe, 10 GbE)

nzbfast4m 33s
NZBGet 26.27m 58s · +75%
SABnzbd 5.0.419m 32s · +329%
rustnzb 1.3.4no output¹
nzbfastNZBGet 26.2SABnzbd 5.0.4rustnzb 1.3.4
time to usable file4m 33s7m 58s (+75%)19m 32s (+329%)none¹
GB on the wire169.6169.8169.7186.5
peak RSS1.4 GB²1.5 GB1.8 GB0.6 GB

¹ rustnzb finished moving bytes at 5m 42s having pulled 186.5 GB (10% more wire than anyone) but left no extracted media, its third straight failed round on this post. · ² nzbfast's memory follows its configured budget, not the job: this round ran the default auto budget and peaked at 1.4 GB; a deliberately huge 64 GB budget buys only 4% (4m 22s), and capped at 1 GB the same 190 GB job still completes (see the low-memory ladder below). On the earlier East Coast round (~2.4–3 Gbps line) the same scenario ran 9m 00s vs NZBGet +30% and SABnzbd +111%. The gap holds across line speeds.

Scenario 2 · the gap grows with size

Time to usable file, by job size

One-pass means no post-download verify/unpack pass, so the bigger the job, the further ahead it lands. Same-machine sequential runs:

JobnzbfastNZBGetSABnzbd
7.4 GB REMUX (Europe, 10 GbE)13.7 s17.3 s (+26%)19.0 s (+39%)
35 GB obfuscated 4K (Europe)67 s108 s (+61%)285 s (+325%)
87 GB 4K (East Coast)272 s370 s (+36%)708 s (+160%)
87 GB on a 97 GB-free disk (Europe)3m 08scannot run²cannot run²
190.6 GB (East Coast)9m 00s11m 43s (+30%)19m 02s (+111%)

² Their peak footprint (volumes + unpacked output simultaneously, ~156 GB) exceeded the 97 GB free. One-pass needs 1× the content size: it halves the disk you need, not just the time.

Scenario 3 · obfuscated post

35 GB hash-named 4K → usable mkv (East Coast)

nzbfastNZBGetSABnzbdrustnzb
time to usable file96 s153 s (+59%)259 s (+170%)no usable file³
peak RSS1.55 GB3.7 GB8.8 GB3.6 GB

³ rustnzb downloaded in 119 s, marked the job Completed, and shipped the raw obfuscated volumes: no rename, no extraction. nzbfast deobfuscated from PAR2 metadata and extracted in-stream, zero read-back blocks.

Scenario 4 · queue of three

Keeping the line lit across a queue (East Coast, ~43 GB)

nzbfastrustnzbNZBGetSABnzbd
time to finish the queue122 s136 s162 s277 s
line idle (<20 MB/s)2 s (2%)16 s (12%)0 s168 s (61%)

Three shapes of the same problem: nzbfast's tail-overlap keeps the line busy edge-to-edge; NZBGet never idles but runs ~35% slower while unpacking concurrently; SABnzbd downloads fast, then leaves the line dark 61% of the time during serial post-processing. In the resilience variant (one job with encrypted RAR headers), SABnzbd's queue wedged on the encrypted job and only 1 of 3 jobs ever completed; nzbfast parked it with a clear message and finished the rest.

The honest column

The legs we don't win

Both legs that used to sit here have been re-measured on the shipping build and neither is a loss any more: the damaged store-mode post now takes us 30 s against NZBGet's 38 s, and par-only reconstruction now completes in 9 s where it took 19 s, on a leg where NZBGet returns in the same time but delivers nothing. We are leaving the section here rather than deleting it. This is where our losses go, and the next round that finds one will put it back.

Why show a loss at all? Because the wins are only believable next to it. Every number on this page comes from the same interleaved runs, and a leg we lose stays published until a re-run replaces it.

Scenario 6 · starve it of RAM

The low-memory ladder: 190 GB in ~1.1 GB of RAM

The same four jobs, re-run at hard memory budgets of 2 GB, 1 GB and 256 MB: what the auto-sizer would pick on an 8 GB box, a 4 GB box, and a 2 GB NAS. Every leg produced a correct, fully verified, extracted file; peak RSS tracked the budget, not the job. Time to usable file, 10 GbE line:

Job sizeplenty of RAM2 GB budget1 GB budget256 MB budget
7 GB15 s15 s15 s15 s
35 GB65 s70 s70 s65 s
87 GB148 s206 s196 s180 s
190 GB330 s427 s402 s411 s

The 20–40% premium on the big jobs is a 10 GbE artifact: spilled blocks only cost time when the line outruns the disk. The same 87 GB job at the same budgets on a ~2.4 Gbps line measured −1% to +7%, noise. On a typical home connection a small budget is close to free at any job size. A NAS profile (2 connections, 256 MB budget) finished the 35 GB job in 0.4 GB peak RSS. A 2 GB NAS can run this. No other client offers a memory ceiling at all.

Scenario 7 · archives inside archives

Ten nested shapes: who finishes without you

Posts increasingly arrive nested: a RAR inside a RAR, a 7z tucked into a store archive, a ladder of layers, a password chain. This round grades what's left for the operator. auto means every payload extracted, byte-identical, no hands; manual means the client reported success but left an inner archive sitting in the output directory for you to open yourself.

shapenzbfastSABnzbdNZBGetrustnzb
store RAR inside store RARautoautomanualmanual
compressed RAR inside store RARautoautomanualmanual
7z inside a store RARautoautomanualmanual
5-level ladder, 6 payloadsauto · 6/6manual · 3/6manual · 1/6manual · 1/6
password chain, 3 encrypted levelsauto · 3/3asks for a passwordasks for a passwordfailed
auto-complete, all ten shapes8/106/102/102/10

Loopback rig, machine-generated corpus, all four clients on the same machine, graded by content hash, so a client that renames the payload still gets credit. Because inner layers are denested on the fly, nzbfast holds one ~1.5 GB copy on disk where write-out-and-unpack clients hold ~3 GB, and finishes these legs in 1–2 s against 4–8 s. On the password chain, each layer's password ships in a file the layer above it extracts: nzbfast reads it and unlocks all three levels; the others stop and wait for you to type it. The two shapes it doesn't auto-complete are graded harshly on purpose: a 10-level ladder past its default depth cap and a post damaged at all three levels. On both it recovers more payloads than any other client, but exits nonzero instead of calling a partial job a success, so both count as failures here.

What a job costs you

Peak disk for a 1.5 GB payload

The one-pass claim is about disk as much as speed, so this is it measured rather than asserted: the highest the working directory ever got during the nested runs, polled twice a second. Reading it once at the end would be meaningless, because a client that deletes its volumes after extracting would look like it never wrote them.

shapenzbfastNZBGet 26.2rustnzb 1.3.4SABnzbd 5.0.4
store RAR inside store RAR1538153817743080
compressed inner layer1536153616743102
RAR inside RAR, depth 21536153617143076
7z wrapped in a store RAR1503153617223102

Megabytes, lower is better. NZBGet matches us here and it is worth saying why: it is running with DirectUnpack and DirectWrite on, which is how we configure every competitor, and on these shapes that is enough to reach one copy on disk. SABnzbd holds two. The gap that remains is the one the pipeline was built for: we never materialise the volumes at all, so the peak is the payload itself rather than the payload plus the archive that carried it.

Scenario 8 · five clients, reproducible content

Client ceiling: 9.68 GB served from RAM, and you can rebuild it

Every leg above runs against commercial providers, so you have to take our word for the line conditions. This one you can rebuild yourself: the content is Blender's open movies (Tears of Steel 4K, Sintel, Big Buck Bunny 4K at 60 and 30 fps), CC-BY 3.0, packed store-mode RAR plus 10% PAR2 into 53 files and 14,521 articles, served over loopback NNTP from RAM by a rig in this repository. No provider is involved, so this measures the client itself, with provider variance removed rather than averaged out.

Because the articles come from memory, the absolute times are far shorter than any real download and are not comparable to the provider legs above. Read the ratios and the disk column, not the seconds.

clienttime to finishconnectionspeak diskvs nzbfast
nzbfast5 s88.6 GBbaseline
Weaver (warmed)8 s120 (auto-ramp)17.9 GB1.6× slower
NZBGet 26.212 s1617.6 GB2.4× slower
SABnzbd 5.0.414 s817.6 GB2.8× slower
rustnzb 1.3.423 s818.7 GB4.6× slower

Time to finish runs from starting the job to all four videos being on disk, verified and extracted. Peak disk is the most disk the client ever occupied at any instant, sampled twice a second, and it is the column that matters most here: one-pass needs about 1× the content, everything else about 2×. All five ended holding the same 8.6 GB once they had tidied up, which is exactly why the peak is the interesting figure. Every client produced all four payloads sha256-identical to source. Each is shown at whichever connection count made it fastest (8, 16 and 32 were tried on each; nzbfast was flat at all three, so more connections would not have helped it).

Every competitor at its documented best. A rival must never lose because we misconfigured it, so each client's settings are published with the round. Two are easy to get wrong and worth knowing if you run your own: SABnzbd rewrites its own ini at startup and reverts pipelining_requests to the shipped 1, so pipelining has to be set over the API afterwards and read back to confirm; and a standalone NZBGet -c config inherits NZBGet's built-in defaults rather than the values in its shipped conf, which silently leaves the article cache off. Both ran with those corrected. Weaver is measured warm, because it auto-ramps its connection count and tunes its pools on the first job and its download CLI never exits, so it runs as a persistent daemon with a discarded warm-up pass. Its 8 s is therefore a warmed daemon at 120 connections against our cold one-shot at 8. That is each client at its best by our own rule, but the asymmetry is real and we would rather state it than bury it.

Peak disk is polled twice a second rather than read once at the end, which matters more than it sounds: every client here deletes its volumes after extraction, so all five finish holding the same 8.6 GB and four of them look one-pass if you only measure the aftermath. Polled through the run, four peak near 18 GB. For anything that self-cleans, report the peak, not the leftovers.

Component shootouts

The more technical benchmarks, for people who like more data

Repair (PAR2) and unpack (RAR) are our own native code rather than bundled third-party binaries, so we also race them standalone against the dedicated tools on identical corpora, on three machines spanning what a reader might actually own. A time only counts when the output is byte-identical to the source payload: every RAR figure below was sha256-checked against the source, and every repaired file against the pristine set.

3 machines, laptop to 32-core 8 RAR archive shapes 6 extractors raced best of 3 interleaved, warm cache

RAR extraction: 8 archive shapes, 6 tools

Each bar is our time as a fraction of unrar 7.23, RARLab's own reference implementation and the fastest of the field on most shapes. Full track = unrar. 32-core desktop, best of 3, tools interleaved inside each round. Seven bars, not eight: RAR4 cannot be created by rar 7.x, so that shape ran on the laptop only and is in the table below.

400 small files0.07 s vs 0.30 · 4.3×
solid0.15 s vs 0.33 · 2.2×
encrypted0.48 s vs 0.79 · 1.6×
big 3-volume0.47 s vs 0.73 · 1.6×
repetitive0.03 s vs 0.04 · 1.3×
128 MB dict0.70 s vs 0.90 · 1.3×
store0.05 s vs 0.05 · tie

The whole field, seconds, lower is better. The same archive shapes on all three machines, seven on the desktops and eight on the laptop. Archives were created by official rar 7.23 so no tool is judged on input from its own encoder. rarpar is Weaver's own RAR and PAR2 code, built from source at a5de0d3; we pin the commit rather than a version because its crates carry three different version numbers.

shapenzbfastunrar 7.23rarparunarrars 0.4.7bsdtar
High-end desktop, 32 cores
store 200 MB0.050.050.050.120.140.07
big, 3 volumes0.470.730.742.122.45wrong output²
400 small files0.070.300.351.241.352.37
solid0.150.330.381.291.842.39
repetitive0.030.040.030.080.140.19
encrypted0.480.790.732.915.88unsup
128 MB dictionary0.700.900.962.632.83unsup
Older desktop, 20 cores
store 200 MB0.050.050.060.140.160.07
big, 3 volumes0.591.020.892.593.08wrong output²
400 small files0.090.390.441.451.722.81
solid0.190.420.471.492.432.84
repetitive0.030.050.040.100.170.22
encrypted0.601.120.923.647.56unsup
128 MB dictionary0.781.271.113.093.44unsup
Laptop, 14 cores / 20 threads, Windows⁴
store 200 MB0.080.160.16no CLI0.240.17
big, 3 volumes0.661.281.10no CLI6.16wrong output²
400 small files0.291.292.14no CLI4.262.27
solid0.711.622.15no CLI20.912.75
repetitive0.070.140.09no CLI0.280.14
encrypted0.661.301.13no CLIfailunsup
RAR40.891.51reject³no CLI2.30reject³
128 MB dictionary0.851.421.32no CLI7.55unsup

The margins are widest on the laptop, not the 32-core box: small-files 4.4× and solid 2.3× there versus unrar. The parallel decode paths scale into threads that a single-threaded extractor cannot use, so the gap grows on modest hardware rather than shrinking. rars 0.4.7 is the upstream crate we forked, shown unmodified: our fork is 3× to 16× faster than it, which is the extraction work in one column. ² bsdtar has no RAR5 multi-volume support and silently produced a truncated file, so that leg is a correctness failure, not a slow time. ³ rar 7.x can no longer create RAR4, so that one archive comes from the rars encoder (unrar-validated); several tools reject it, and it is the one shape the two desktop rounds could not rebuild, so it appears on the laptop only. ⁴ unar has no Windows CLI, so the laptop field is five tools.

Dates, because they are not all the same. The two desktop groups were re-measured for 1.0.8 on one freshly built corpus, with every tool run from the same staged binaries so no machine raced a different version. The laptop group is the earlier round and is unchanged. That is deliberate rather than lazy: extraction performance did not move between 1.0.7 and 1.0.8, which we checked by racing both builds head to head on every shape and finding them level, so the laptop figures still describe the shipping build. Re-running that rig would have changed the corpus without changing the answer.

PAR2 verify and repair: 1 GiB set, 101 damaged blocks

Corpus: 1 GiB payload packed store-mode into 21 RAR volumes, then a classic PAR2 set at 1 MiB blocks and 10% redundancy, then a fixed 101-block damage map across 6 volumes for the repair leg. Bars are scaled within each machine, since the hardware differs. Lower is better.

Clean verify

High-end desktop, 32 cores

nzbfast0.34 s
par2-turbo0.90 s
par2cmdline3.10 s

Older desktop, 20 cores

nzbfast0.41 s
par2-turbo1.08 s
par2cmdline3.68 s

Laptop, 14 cores, Windows

nzbfast1.12 s
par2-turbo1.48 s
MultiPar1.73 s

Repairing 101 damaged blocks

High-end desktop, 32 cores

nzbfast0.88 s
par2-turbo2.07 s
par2cmdline5.49 s

Older desktop, 20 cores

nzbfast1.28 s
par2-turbo2.66 s
par2cmdline7.55 s

Laptop, 14 cores, Windows

nzbfast2.57 s
par2-turbo3.62 s
MultiParno repair⁵

Fastest verify and fastest repair on all three machines, against the SIMD par2cmdline-turbo fork, classic par2cmdline 1.2.0 and MultiPar's par2j. Every repaired volume came out byte-identical to the pristine set. The gap is widest on the desktops because our repair path spreads the Reed-Solomon fold across cores; on 14 cores it is 1.4× rather than 2×. Weaver's rarpar was raced on the two desktops as well and lands behind classic par2cmdline on repair: 4.91 s and 5.87 s against our 0.88 s and 1.28 s. ⁵ par2j verifies this set fine but returned a non-zero status on the repair leg in our harness; it likely wants a different invocation and we did not chase it, so read that row as "not measured", not as a failure of MultiPar.

Light damage, the common field case. A handful of failed articles is far more typical than 101 dead blocks, so this round adds a 3-block repair leg: 0.58 s against par2-turbo's 1.12 s on 32 cores, 0.69 s against 1.37 s on 20 cores. It is worth saying what did not move. The 1.0.8 repair rewrite spreads the fold across rows and columns, and rows are the missing-block count, so light damage is exactly where the old code left a big machine idle. In the fold microbenchmark alone that is a 3.65× speedup. End to end it is worth almost nothing, because the fold is about a millisecond of a run dominated by reading and MD5-ing a gigabyte. Both halves are true and the second one is the one that reaches users.

RAR recovery records: repairing without PAR2

When PAR2 cannot cover the damage, the recovery record inside the RAR itself is the last line of defence. Until 1.0.8 ours failed on any archive over about 13 MB, so this leg could not be run at all. Damage is three 3,000-byte holes at 20%, 50% and 80% through the protected region. Both tools produced output byte-identical to the pristine file, and ours is byte-identical to what rar r itself writes.

archivenzbfastrar 7.23 repair
16 MB0.150.261.7× faster
32 MB0.260.441.7× faster
128 MB0.891.031.2× faster
512 MB3.462.231.6× slower

We lead to about 128 MB and RARLab pulls ahead by 512 MB, so the crossover sits somewhere in the low hundreds of MB. That last row is a loss and it stays on the page: our repair streams rather than holding whole volumes in memory, which costs throughput at the top end and buys a bounded working set. On the 8 GB to 20 GB volumes a daemon actually meets, holding the volume is not an option, so it is the right trade even where it loses. Measured against the buffered path on the same archive: 1.4× slower to run, 2.3× less peak memory.

What else moved in 1.0.8, and where it does not show. Three more engine changes landed that these corpora cannot see, listed here so the numbers above are not read as the whole story: rebuilding a .rev volume now does one erasure solve instead of one per byte; RAR5 archives with tens of thousands of members resolve each member once rather than walking the list per worker (3× less processor time at 40,000 members); and the RAR1.3 bit reader works a word at a time (2×). None of them appear above, because the shapes here have 400 members, no .rev set, and no RAR1.3.

What we deliberately do not do: we never create PAR2. A downloader has no reason to, and ParPar owns that leg. We also buy speed with memory on both engines: extraction peaks around 240 MB against unrar's 41 MB, and verify around 126 MB against turbo's 7 MB, because these are the inline engines that ride a live download rather than standalone one-shots. If you want the smallest possible resident set for a standalone job, the dedicated tools still win that column.

Every number on this page is a dated run with its exact command and conditions recorded, negative results and abandoned approaches included. These pages are the published record, and they get fleshed out as further rounds land.

Capability, not micro-benchmarks

What each client can do

nzbfastSABnzbd 5NZBGet 26rustnzbUsenappNewsbin
pipelined NNTPyesoff by defaultnoyes--
full verify during downloadevery blockafterquick-checkafterafterafter
extract during downloadin-stream, no volumes on diskdirect unpack⁴direct unpack⁴unreliable⁵nono
disk needed for an N-GB post~1×N~2×N~2×N~2×N~2×N~2×N
pre-download completability verdictblock-exactnohealth %noarticle checkno
bounded memory (never swap)budgeted9.3 GB @ 190 GBcache settingno--
check the file at any point while downloadingyesnononosequentialno
built-in indexer + poster wallyes, keylessnononosearch UIgroup browser
Sonarr/Radarr drop-inSAB API + Newznabnativenativepartialnono
phone remotes (nzb360/LunaSea)via NZBGet RPCyesyesnonono
watchlist auto-grab + upgradesbuilt invia *arrvia *arrnoWatchdogrules
single self-contained binaryyesPythonyesyes.app.exe
open sourceGPL⁶GPLGPLyespaidpaid
platformsmac/win/linux/dockermac/win/linuxmac/win/linuxlinux/winmac onlywin only

⁴ Direct unpack still materialises the volumes first: 2× writes and 2× disk. ⁵ rustnzb shipped obfuscated volumes marked "Completed" in our round (its unpack also hangs with RARLab unrar unless disabled). ⁶ GPL-3.0-or-later. Usenapp/Newsbin are single-platform commercial readers with downloader features; they're listed because people ask, not because they compete on speed.

Transport proof

The engine saturates real lines

Standing rule: every performance claim cites the conditions it ran under, negative results and wrong turns included.