Downloadzahlen auf crates.io: 80 % unserer Downloads kamen mit einer neuen Version

Kurz gesagt: Am 17. Oktober 2026 habe ich jede tägliche Downloadzahl abgerufen, die crates.io für meine 69 Rust-Crates gespeichert hat. Über 89 Tage kamen 3.676 Downloads zusammen, und 80,1 % davon fielen auf den Tag, an dem eine neue Version erschien, oder auf den Tag danach. Eine neue Version sammelt in ihren ersten 24 Stunden rund 13 Downloads ein, egal was drinsteckt, danach ist Funkstille. Externe Crates, die von einem der 69 abhängen: null. Die Zahl, die dir wirklich verrät, ob Leute dein Crate nutzen, ist die Ruhetags-Baseline, und die lag bei uns bei 339 Downloads, etwa 3,8 pro Tag.
Die kurze Antwort für alle, die danach suchen: Die Downloadzahl auf crates.io gibt an, wie oft die .crate-Datei eines Crates vom CDN von crates.io abgerufen wurde, gezählt anhand der Request-Logs des CDN (crates.io hat im März 2024 auf logbasierte Zählung umgestellt). Seit dem 29. Oktober 2025 zählen nur noch Anfragen, die so aussehen, als kämen sie von cargo (oder die gar keinen User-Agent mitschicken). Sie zählt nicht Nutzer, Installationen oder Projekte. Die CI eines einzelnen Entwicklers, die 30-mal am Tag cargo build auf einer frischen Maschine ausführt, erzeugt 30 Downloads pro Tag. Eine Person, die dein Crate einmal installiert und im lokalen Cache behält, erzeugt genau einen, für immer.
Was steckt also tatsächlich in der Zahl eines kleinen Crates? Unten findest du eine frische Messung an einem echten Portfolio, das Skript, das die Daten abruft (kopier es und lass es auf deine eigenen Crates los), und wie du dein eigenes Diagramm liest, ohne dir in die eine oder andere Richtung etwas vorzumachen.

Woher die 69 Crates kommen
Etwas Kontext, denn die Form der Daten ergibt sich direkt daraus, wie diese Crates veröffentlicht wurden. Ich pflege einen ganzen Haufen Rust-Bibliotheken und -Tools: fin-primitives (Bausteine für Trading), tokio-prompt-orchestrator (ein LLM-Proxy mit Deduplizierung und Circuit Breaker), proof-engine (eine OpenGL-Game-Engine) und CoreScout, einen MCP-Server, der in einen Workspace aus 33 Crates aufgeteilt ist.
Sie gingen in drei Schüben raus: 51 Versionen im März 2026, 116 im September und 68 im Oktober, insgesamt 235 Versionen. Der Oktober-Schub war ein einziger großer Release-Lauf am 4. Oktober, nachdem KI-Coding-Agents jedes Crate aktualisiert hatten und ich am Ende alles in einem Rutsch veröffentlicht habe. Dieser eine Tag spielt später eine große Rolle.
Gesamtzahl seit Beginn, als ich sie am 17. Oktober um 7:10 Uhr ET abgerufen habe: 4.815 Downloads. Die Angabe "recent downloads" von crates.io (letzte 90 Tage) lag bei 3.677. Mein Ziel für diese Crates sind 100.000, also lautet die ehrliche Frage: Wie viel von den 4.815 sind Menschen?
Hol dir die Zahlen selbst, in 40 Zeilen
crates.io hat eine öffentliche JSON-API. Sie ist nicht offiziell versioniert, aber die Website ruft sie selbst auf, und die Richtlinie zum Datenzugriff verlangt zwei Dinge: höchstens eine Anfrage pro Sekunde und einen User-Agent, der sagt, wer du bist. Drei Endpunkte liefern alles:
/api/v1/crates?user_id=N: jedes Crate eines Nutzers, mit Gesamt- und 90-Tage-Summen./api/v1/crates/<name>/downloads: tägliche Downloads der letzten 90 Tage, aufgeteilt nach Version (ältere Versionen landen gesammelt inextra_downloads)./api/v1/crates/<name>/reverse_dependencies: welche veröffentlichten Crates von diesem abhängen.
Das ist das Skript, das ich heute Morgen laufen ließ (pull.py, nur um die Auswahl der JSON-Felder gekürzt). Bei einem 429 bricht es sofort ab, statt es erneut zu versuchen, denn ein höflicher Scraper diskutiert nicht mit einem Rate Limit:
UA = "tensorust-deepdive-research (contact: hello@tensorust.com)"
last = [0.0]
def get(path):
wait = 1.05 - (time.time() - last[0]) # stay under 1 request/second
if wait > 0:
time.sleep(wait)
last[0] = time.time()
req = urllib.request.Request("https://crates.io" + path, headers={"User-Agent": UA})
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
except urllib.error.HTTPError as e:
if e.code == 429:
print("429 - stopping"); sys.exit(2)
raise
user = get("/api/v1/users/mattbusel")["user"]
crates = get(f"/api/v1/crates?user_id={user['id']}&per_page=100")["crates"]
for c in crates:
n = c["name"]
dl = get(f"/api/v1/crates/{n}/downloads")
vers = get(f"/api/v1/crates/{n}/versions?per_page=100")
rev = get(f"/api/v1/crates/{n}/reverse_dependencies?per_page=100")
# ... store dl["version_downloads"], dl["meta"]["extra_downloads"], versions, rev
69 Crates mal drei Aufrufe, einer pro Sekunde, dauerten etwa dreieinhalb Minuten. Danach folgte ein zweiter Durchlauf mit 69 Aufrufen, um Versions-IDs den Versionsnummern und Veröffentlichungszeiten zuzuordnen, denn der Downloads-Endpunkt beschriftet jede Zeile mit einer numerischen Versions-ID statt mit "2.15.0".

Wenn du mehr als ein paar hundert Crates hast (oder jedes Crate der Registry willst), bombardier die API nicht: crates.io veröffentlicht alle 24 Stunden einen Datenbank-Dump (static.crates.io/db-dump.tar.gz), der die Download-Tabelle pro Tag und Version für die letzten 90 Tage enthält.
Was dir die Seite auf crates.io zeigt
Hier das untere Ende der Seite von fin-primitives, meinem meistgeladenen Crate. Schau dir das Diagramm an, bevor du die Zahlen liest: den ganzen Sommer über ein flaches Gezappel von 0 bis 3 pro Tag, dann hohe Spitzen in der letzten Septemberwoche und der ersten Oktoberwoche, jede Spitze in einer anderen Farbe. Jede Farbe ist eine Version.

Das Diagramm ist ehrlich, aber es gilt pro Crate. Bei 69 Crates kannst du nicht 69 Diagramme mit bloßem Auge prüfen, also habe ich jeden Crate-Tag im 90-Tage-Fenster einer von drei Kategorien zugeordnet.
Die drei Arten von Downloadtagen
Die Regel ist einfach und vollständig mechanisch:
- Veröffentlichungsfenster: Das Crate hat an diesem UTC-Tag oder am Vortag eine Version veröffentlicht.
- Sweep-Tag: keine Veröffentlichung, aber mindestens die Hälfte aller meiner damals existierenden Crates wurde am selben Tag heruntergeladen.
- Ruhig: alles andere.
Der Kern des Klassifizierers, aus analyze.py:
for n, c in C.items():
for v in c['downloads']['version_downloads'] + c['downloads']['meta']['extra_downloads']:
d = dt.date.fromisoformat(v['date'])
if any(0 <= (d - p).days <= 1 for p in pub[n]):
cat[v['date']][0] += v['downloads'] # publish window
elif v['date'] in sweeps:
cat[v['date']][1] += v['downloads'] # sweep day
else:
cat[v['date']][2] += v['downloads'] # quiet
Und das Ergebnis für den Zeitraum 20. Juli bis 16. Oktober 2026 (89 volle UTC-Tage, 3.676 Downloads):

2.945 Downloads (80,1 %) fielen in ein Veröffentlichungsfenster. 392 (10,7 %) kamen an sechs Sweep-Tagen. 339 (9,2 %) waren Downloads an ruhigen Tagen. Der stärkste Einzeltag war der 4. Oktober, der Release-Lauf: 68 veröffentlichte Versionen, 1.195 Downloads.
Anders gesagt: Hätte ich die Versionen aus September und Oktober nie veröffentlicht, läge die 90-Tage-Zahl irgendwo bei 730, nicht bei 3.676.
Eine neue Version bekommt rund 13 Downloads, dann nichts mehr
Um zu sehen, was eine Veröffentlichung für sich allein wert ist, habe ich jede Version genommen, die innerhalb des Fensters erschienen ist und danach mindestens eine Woche Daten hat (181 Versionen), und ihre Downloads nach Tagen seit der Veröffentlichung aufgereiht.

Durchschnittliche Downloads an Tag 0: 13,45 (Median 10). Tag 1: 1,21. Tag 2: 0,02. 86,9 % der Downloads einer Version in der ersten Woche kommen an Tag 0 oder Tag 1. Die kleinste Summe aus Tag 0 und Tag 1 lag bei 8, die größte bei 66, der Median bei 12.
Verräterisch ist die Untergrenze. Über alle 235 jemals veröffentlichten Versionen hinweg liegt der niedrigste Gesamtwert einer einzelnen Version bei 9. Der Median liegt bei 18. Ich habe 19 Crates, die nur eine einzige Version hatten, darunter interne Infrastruktur-Crates wie corescout-cli und corescout-lineage, von denen außerhalb dieses Projekts niemand einen Grund hat zu wissen. Ihre Gesamtwerte reichen von 10 bis 28, Median 15. Irgendetwas ruft jede neue Version innerhalb von Stunden nach der Veröffentlichung ab, ob nun je ein Mensch die README liest oder nicht.
Was ist dieses Etwas? Die Daten verraten es nicht. Meine Vermutung, und es ist eine Vermutung: Registry-Mirrors und Build-Farmen, die dem crates.io-Index folgen und neue Versionen abrufen, sobald sie auftauchen, dazu Sicherheits- und Lizenzscanner. Der User-Agent-Filter von 2025 wurde geschrieben, um Mirrors auszusortieren, also ist alles, was ihn übersteht, entweder cargo selbst oder ein Client, der keinen User-Agent schickt. docs.rs baut außerdem automatisch die Dokumentation für jede neue Version. Ob dieser Abruf mitgezählt wird, konnte ich anhand der öffentlichen Doku nicht bestätigen, deshalb behaupte ich es auch nicht.
Die Konsequenz ist sehr praktisch: Auf crates.io sagt die Zahl deiner veröffentlichten Versionen deine Downloads besser voraus als alles am Code. Über meine 69 Crates hinweg liegt die Korrelation zwischen Versionsanzahl und Gesamtdownloads bei 0,82. Deshalb führt fin-primitives (13 Versionen), und meine eigentlich interessanteren Crates liegen dahinter.
Sweep-Tage: wenn jedes Crate auf einmal abgerufen wird
Die zweite Kategorie hat mich mehr überrascht. Am 9. Oktober wurde nichts veröffentlicht, und trotzdem wurden alle 69 Crates am selben Tag heruntergeladen, insgesamt 184 Downloads. Am 13. Oktober: 56 von 69 Crates, meist mit je einem Download. Das ist kein Mensch. Ein Mensch installiert ein Tool und dessen Abhängigkeitsbaum, nicht an einem Nachmittag ein Statistik-Crate, ein Trading-Crate, eine Game-Engine und einen TFT-Berater.

Sechs Tage im Fenster passen ins Muster: der 3. August (17 von 17 damals existierenden Crates), der 29. September sowie der 5., 9., 13. und 15. Oktober. Einige der späteren tendieren zur CoreScout-Familie: Am 6. und 15. Oktober waren die Top-Crates corescout-core, corescout-mirror und corescout-memory, genau das, was du sehen würdest, wenn etwas den Abhängigkeitsbaum eines CoreScout-Binaries auflöst. Das führt zu dem Multiplikator, den niemand erwähnt.
Workspaces vervielfachen die Zahl
CoreScout ist ein Cargo-Workspace, und wenn du einen Workspace auf crates.io veröffentlichst, wird jedes Member zu einem eigenen Crate. Hier die echte Root-Cargo.toml (Auszug):
corescout-core = { version = "1.2.0", path = "crates/core" }
corescout-mirror = { version = "1.2.0", path = "crates/mirror" }
corescout-substrate = { version = "1.2.0", path = "crates/substrate" }
corescout-memory = { version = "1.2.0", path = "crates/memory" }
corescout-represent = { version = "1.2.0", path = "crates/represent" }
corescout-science = { version = "1.2.0", path = "crates/science" }
corescout-core hat 25 abhängige Crates, allesamt seine eigenen Geschwister. Laut den Reverse-Dependency-Daten hat corescout-mcp 16 meiner anderen Crates irgendwo in seinem Abhängigkeitsbaum, also dürfte ein einziges cargo install corescout-mcp auf einer frischen Maschine als bis zu 17 Downloads auftauchen, verteilt auf 17 Crate-Seiten. Über alle 69 Crates hinweg listet die Reverse-Dependency-API 178 abhängige Versionen, und jede einzelne davon gehört mir.
Das ist der bittere Teil. Die Crates mit den meisten Abhängigen wirken am meisten "genutzt" (11 Crates mit fünf oder mehr Abhängigen hatten im Median 6 ruhige Downloads, die 25 Crates ohne Abhängige hatten in 89 Tagen im Median null), und das ist komplett meine eigene Verdrahtung.
Die Ruhetags-Baseline: die einzige Zahl, die Menschen bedeutet
Zieh die Veröffentlichungsfenster und die Sweeps ab, und es bleiben 339 Downloads in 89 Tagen, etwa 3,8 pro Tag über alle 69 Crates. Das ist das, was am ehesten "irgendwer, irgendwo hat heute mit meinem Code gebaut" bedeutet. Es ist nicht null, und es steigt: Das Portfolio lag Ende Juli im Schnitt bei 1,7 ruhigen Downloads pro Tag, im August bei 3,4, im September bei 2,8 und in der ersten Oktoberhälfte bei 8,1 (mit deutlich mehr Crates, also den Oktober mit Vorsicht genießen).
Ein Crate leistet den Großteil der Arbeit. fin-primitives allein macht 128 der 339 ruhigen Downloads aus (38 %), an den meisten Tagen seit Juli ein oder zwei, lange vor dem Release-Stapel dieses Herbsts. Ich tippe darauf, dass eine Handvoll Leute oder eine CI-Pipeline regelmäßig dagegen baut. Das ist ein echtes Signal, und genau das würde mitsamt dem Rauschen im Müll landen, wenn man alles pauschal als "Bots am Veröffentlichungstag" abtut.
Und die Zahl, die jede Diskussion beendet: externe Reverse Dependencies: 0. Kein veröffentlichtes Crate außerhalb meiner eigenen nutzt eines der 69. Der crates.io-Index von ecosyste.ms ist dafür eine gute zweite Quelle, weil er auch Repositories erfasst, die von einem Crate abhängen, ohne selbst eines zu veröffentlichen.
So machst du das mit deinen eigenen Crates
- Lies deine Zahl als drei Zahlen. Veröffentlichungsfenster, Sweep und ruhig. Lass den Klassifizierer von oben laufen (oder schau dir einfach die Farben pro Version auf deiner Crate-Seite an). Nur die ruhige Linie sagt etwas über Nutzer.
- Rechne mit etwa 10 bis 15 Downloads pro Version, ganz umsonst. Zeigt ein brandneues Crate am ersten Tag 12 Downloads, hat es noch niemand gefunden, und das ist in Ordnung. Zeigt es 12 an einem beliebigen Dienstag drei Wochen später, hat es wahrscheinlich jemand gefunden.
- Veröffentliche nicht, um die Zahl aufzupumpen. Es funktioniert (wir haben gerade gemessen, dass es funktioniert), und genau deshalb taugt die Zahl nicht als Beliebtheitsmaß, und deshalb schaut sich jeder, der dein Crate bewertet, stattdessen die Abhängigen und die jüngste Aktivität an.
- Zähl Abhängige, nicht Downloads. Der Dependents-Tab auf crates.io, die Reverse-Dependency-API und "Used by" auf GitHub zeigen echte Verbreitung. Ein Crate im Abhängigkeitsbaum von jemand anderem ist mehr wert als tausend Abrufe am Veröffentlichungstag, denn jeder ihrer CI-Läufe lädt deins mit herunter, für immer.
- Denk daran, dass ein Workspace die Zahl um seine Breite aufbläht. Wer ein Tool in 30 Crates aufteilt, lässt jede Installation wie 30 Downloads aussehen. Nenn die Zahl des Binary-Crates, wenn du eine ehrliche Schlagzeile willst.
- Ruf die Daten regelmäßig neu ab. Die API speichert pro Crate nur 90 Tage an Tagesdaten. Wenn du einen Trend willst, sichere das JSON jeden Monat. Sobald ein Tag aus dem Fenster fällt, ist die Aufteilung pro Tag für immer weg.
Die Zahlen, alle auf einen Blick
| Messgröße (crates.io-API, abgerufen am 17. Okt. 2026, 7:10 Uhr ET) | Wert |
|---|---|
| Crates / Versionen | 69 / 235 |
| Downloads insgesamt | 4.815 |
| Downloads 20. Juli bis 16. Okt. (89 Tage) | 3.676 |
| Im Veröffentlichungsfenster | 2.945 (80,1 %) |
| An Sweep-Tagen | 392 (10,7 %) |
| Ruhig | 339 (9,2 %), 3,8/Tag |
| Downloads pro neuer Version, Tag 0 (Mittelwert / Median) | 13,45 / 10 |
| Anteil der Downloads der ersten Woche an Tag 0 oder 1 | 86,9 % |
| Niedrigster Gesamtwert einer Version | 9 |
| Korrelation Versionen zu Downloads | 0,82 |
| Externe Reverse Dependencies | 0 |
Fürs Protokoll: Das ist kein "Downloads sind fake"-Artikel. Die Zählregeln sind öffentlich und vernünftig, und die Ruhetags-Baseline ist echt und wächst. Es ist ein "Wisse, welchen Teil der Zahl du gerade anschaust"-Artikel. Der nächste Meilenstein, der mich interessiert, sind nicht 10.000 Downloads, sondern das erste Crate mit einem externen Abhängigen. Ich rufe die Daten in 30 Tagen erneut ab und veröffentliche den Vergleich.
Wenn du selbst Crates pflegst: Wie sieht deine Ruhetags-Baseline im Vergleich zu deiner Gesamtzahl aus? Mich interessiert ernsthaft, ob 80 % im Veröffentlichungsfenster für kleine Crates normal sind oder ob meine Release-Gewohnheiten das verschlimmert haben.
Mehr aus denselben Projekten: der semantische Cache in tokio-prompt-orchestrator, 20 Coding-Agents auf einem PC betreiben (die Agents, die diese Crates aktualisiert haben) und Bevy-Instancing mit 639.000 Einheiten.
Zuerst hier auf tensorust.com erschienen am 17. Okt. 2026. Auch auf dev.to. Passend dazu: Prüf ein beliebiges Crate: echte Downloads vs. Bots am Release-Tag, Alle 69 Crates auf crates.io, Tools für den Betrieb von Coding-Agents, Der semantische Cache in tokio-prompt-orchestrator.
Weiterlesen
- Dev · 23. Okt. 2026 · 13 Min. LesezeitEine UUIDv7-Bibliothek wählen, die die Reihenfolge hält: 10 getestet, .NET scheitert zu 50 %
- Gaming · 19. Okt. 2026 · 18 Min. LesezeitBalatros Spielstand wird als Code ausgeführt. 1 von 5 beschädigten Spielständen lädt trotzdem
- Dev · 18. Okt. 2026 · 14 Min. LesezeitEine Datenbank in Rust bauen: KI bestand 866K Tests und scheiterte dann an ROLLBACK