nexarr

Newznab meta-search one Go binary

All your Usenet indexers.
One endpoint.

Nexarr fans every search out to all your Newznab indexers, merges the results and strips the duplicates — so Sonarr and Radarr point at one URL instead of a dozen.

SQLite with zero dependencies, or your existing Postgres. No JVM, no runtime.

The problem

Every other aggregator asks each indexer for one page of recent results — and truncates in silence.

You never see what's missing. The same release shows up five times under five slightly different names. And a flaky indexer keeps burning your API quota with nothing to show for it. Nexarr treats correct pagination and fuzzy deduplication as the product — not as details.

What it does

Built for the search, not the demo.

Pagination that doesn't lie

Nexarr walks each indexer to exhaustion instead of stopping at the first short page. A missing result is a bug, not a shrug.

correct-pagination

Fuzzy deduplication

The same release from five indexers, under five names, collapses into one. Spanish and Latin-American dialects are treated as distinct — because they are.

dedup

Honest quotas

Nexarr counts what you spend using the indexer's own reported apilimits — the figure that already includes what your other clients spent. Failing indexers back off and get disabled.

quota + backoff

One binary. Zero runtime.

Go. SQLite with no external dependency, or your existing Postgres — same image, only the driver changes. A one-line docker compose up.

go · sqlite · postgres

Newznab-compatible

Sonarr, Radarr and any other client point at one URL. Capabilities are served without a key, so the *arr Test button just works.

t=caps · t=search

Loud on failure

No enabled indexer, an unreachable database, an unparsable log level — each prints what's wrong and exits non-zero, instead of coming up half-working.

/status

How it works

Up and searching in three steps.

  1. 01

    Run it

    One binary, or one container. SQLite means no external dependency to stand up first.

    cp .env.example .env        # NEXARR_API_KEY is required
    cp config.example.yaml config.yaml
    docker compose up -d        # SQLite, one service
  2. 02

    Add your indexers

    The config file is committable — every secret is an ${ENV} reference. A missing key fails startup instead of silently expanding to empty.

    indexers:
      - name: example
        url: https://indexer.example
        api_key: ${EXAMPLE_API_KEY}
        enabled: true
  3. 03

    Point Sonarr & Radarr at it

    Add one Newznab indexer with your Nexarr key. One search now fans out to all of them, merged and deduplicated.

    # Newznab URL
    http://host:5076/api
    
    curl "http://localhost:5076/api?t=caps"

Benchmark seed 20260731

Measured against NZBHydra2 and Prowlarr.

Three aggregators, four simulated indexers, 30 repetitions per query, on a corpus whose ground truth is exact by construction. The harness is in the repository, so the numbers below are checkable rather than merely stated — including the ones that do not favour us.

99.5%

Recall

NZBHydra2 95.8% on the same corpus

21.1%

Duplicate rate

50.6% fewer repeated rows than NZBHydra2's 42.6%

3.3 MB

Idle memory

209× less than NZBHydra2's 689 MB

7 ms

Cold start

206× faster to first correct answer

Where it is a draw: at realistic indexer latency our p95 is 232 ms against their 236 ms. That gap is smaller than the drift between two runs of the same build, so it is a tie, and the table below marks it as one.

Where it stands v0.1

Usable end to end — with gaps we won't hide.

This is v0.1. It runs the full pipeline in production, and there are things it doesn't do yet. Here's exactly which is which.

Works today

  • nexarr serve runs the whole pipeline, end to end
  • Concurrent fan-out to every enabled indexer, per-indexer timeout
  • Fuzzy deduplication with dialect detection
  • Quota accounting from real apilimits, backoff, auto-disable
  • Newznab feed (XML) + native JSON API + /status page
  • Opaque download links, grab accounting, failover to another copy
  • Optional per-indexer proxy mode and in-memory search cache

Not yet

  • NZB caching — a proxied NZB is served and forgotten (designed, not built)
  • ID translation (IMDB ↔ TMDB ↔ TVDB ↔ TVMaze) — text fallback is in, translation isn't
  • Single-flight — two identical searches arriving at once are still two fan-outs

One URL for every indexer you run.

Requires Go 1.26+. MIT licensed. No JVM, no runtime, no account — just a binary and your config.

git clone https://github.com/nexarr-app/nexarr.git && cd nexarr && make build