← All AI Engineer talks

AI Engineer World's Fair 2026

Serving 2 Million Models Without Melting: Scaling the Hugging Face Hub

Arek Borucki· Machine Learning Platform & Database Engineer, Hugging Face21:39

Read the talk

Serving 2 Million Models Without Melting: Scaling the Hugging Face Hub

How Hugging Face separates metadata from artifacts, prepares names for search, distributes database work, and scales Kubernetes capacity as its model catalog grows.

From a talk by Arek Borucki

Before you start: Familiarity with database queries, replication, and Kubernetes pods will help; the article explains the search and scaling mechanisms as they appear.

What happens when the model catalog outgrows search?

How do you keep a model hub responsive while its catalog grows into the millions? Developers still need to publish, discover, and download models without thinking about the infrastructure behind those actions. Arek Borucki, a machine learning platform and database engineer at Hugging Face, describes the decisions behind that experience. Although the recording’s title says two million models, his account uses a spoken figure of three million.

At the time of the talk, Borucki reports more than 14 million users, three million public models, one million datasets, and 50,000 organizations. He also reports that more than 30% of Fortune 500 companies use Hugging Face in their AI workflows. The opening slide labels the public-model count more precisely as 2.9M+.

Slide lists 14M+ users, 2.9M+ public models, 1M+ datasets, 50K+ organizations, and adoption by 30%+ of the Fortune 500.
Hugging Face’s scale: users, public models, datasets, and organizations.

Borucki puts the model catalog’s growth at roughly 150×, from 20,000 models three years earlier to three million. Major releases such as Llama and DeepSeek generate thousands of derivative models, so a successful release also creates a wave of new repositories to manage.

Datasets follow the same trajectory: Borucki reports 10,000 in 2022, 100,000 in 2024, 500,000 less than a year before the talk, and one million at the time of the talk. Every addition must be stored, indexed, and made searchable. Storage growth therefore becomes a discovery problem, not just a capacity problem.

0:330:57
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:33 · section reference included

The slow end of search matters

At 20,000 models, Borucki recalls, even queries without an index seemed fast enough. At three million, that approach broke down. Users expect search results immediately; a slow catalog gives them a reason to leave. His illustrative calculation is that 1% of 14 million users would mean 140,000 people experiencing slow search. That is a hypothetical affected population, not a measured incident or a conversion from request percentiles into distinct users.

Tail latency becomes a design priority. P50 describes the median request; P99 describes the latency boundary below which 99% of requests fall. Borucki emphasizes P99 because a healthy median can conceal a painful slow tail.

Three slide panels describe expectations for instant results, growth from 20K to 3M models, and the importance of p99 over p50 for 14+M users.
At three million models, search latency and p99 matter.

The response spans several layers: precomputed search tokens, a denormalized MongoDB collection optimized for reads, Lucene-backed search, and Kubernetes autoscaling. Database sharding is the next planned step. Each addresses a different source of work or contention rather than expecting one larger machine to solve everything.

4:094:23
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

4:09 · section reference included

Separate compute, metadata, and model files

A request travels from the frontend to the Hub API, which runs on Kubernetes. The Horizontal Pod Autoscaler adds application pods during traffic spikes and removes them as demand falls. The request then reaches MongoDB Atlas, the source of truth for Hub metadata.

MongoDB stores information about models, not the model binaries themselves. Its responsibilities include users, repositories, model and dataset records, buckets, Spaces information, configuration data, billing, and access control. Model artifacts, tokenizer files, card assets, and configuration files live separately in cloud object storage such as AWS S3.

LayerResponsibility
KubernetesRun and scale Hub application compute
MongoDB AtlasStore and query metadata
Cloud object storageStore model files and other artifacts

This separation lets the team scale metadata independently of binary storage, and compute independently of both. Each component can be optimized for its own workload.

5:415:54
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

5:41 · section reference included

Prepare model names before anyone searches

Consider someone typing llama into the Hub search bar. The request reaches a dedicated MongoDB read collection, not the main repository collection containing all repository data. This separate, denormalized copy is built for reads and listings.

The key optimization happens earlier: model names are tokenized at insertion time rather than query time. For the example identifier meta-llama/llama3.1-8b, the stored array includes tokens such as meta, llama, 3.1, and 8b. Atlas Search uses Lucene-backed autocomplete to match against that prepared representation. The query does not have to start by decomposing every model name.

Borucki inspects the stored representation with findOne, selecting that model identifier and projecting only its search-token array. The useful distinction is between the repository’s full identifier and the smaller searchable pieces stored alongside it: the readable model name remains intact while search gets a representation suited to matching.

7:558:12
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

7:55 · section reference included

Replace regex matching while keeping trending order

The earlier search implementation used MongoDB’s find method with a regex against searchTokens, then sorted matches by descending trendingScore. The query’s structure is compact:

javascript

db.models
  .find({ searchTokens: { $regex: "llama" } })
  .sort({ trendingScore: -1 });

Borucki says the trending score is recalculated every five minutes using downloads and likes; he recalls a seven-day activity window. Matching determines which models qualify, while the trending score determines their order.

MongoDB query with arrows highlighting find, the regex search for llama in searchTokens, and descending trendingScore sorting.
The existing regex search sorts results by trending score.

That approach worked while the dataset was small. As the catalog grew, regex search developed latency problems, prompting the move to Atlas Search and Apache Lucene. In the architecture Borucki describes, a separate process, mongot, wraps Lucene while exposing search through MongoDB’s query interface. This is distinct from MongoDB’s native text indexes and $text queries; core MongoDB does have text-search capabilities, but those are not the Lucene-backed autocomplete path used here.

The replacement uses an aggregation pipeline with $search, names the search index, and applies autocomplete to the token field. It still sorts by trending score. Expressed as a JavaScript helper taking the configured index name, the query shape is:

javascript

function searchLlamaModels(models, indexName) {
  return models.aggregate([
    {
      $search: {
        index: indexName,
        autocomplete: {
          query: "llama",
          path: "searchTokens"
        }
      }
    },
    { $sort: { trendingScore: -1 } }
  ]);
}

The change is in the matching engine, while the product’s popularity-based ordering remains in place.

Borucki reports that the replacement had scaled well so far and resolved the team’s search-bar latency issues; he provides no latency distribution or benchmark workload. The two displayed results have trending scores of 33 and 14, illustrating the retained descending order.

10:0310:20
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

10:03 · section reference included

Keep unnecessary work off the primary

Search is only one database consumer. Borucki describes hundreds of Hugging Face services using MongoDB and a seven-node cluster handling millions of queries, without specifying a time interval. Distributing queries across machines prevents one node from becoming the read bottleneck. All inserts, updates, and deletions still go to the single primary; reads can be spread across other members.

One member is a hidden analytics node. It replicates data from the primary but is invisible to ordinary application routing: the MongoDB driver does not send normal application queries there. The team connects directly to it for reporting and heavy queries. Like the other secondaries, it stays synchronized by following the primary’s operation log, or oplog.

Routing then follows the workload’s requirements:

  • Freshness-sensitive reads: In the described policy, queries requiring strong consistency stay on the primary. Reads that do not require the latest data go to secondaries.
  • Complex aggregations: Pipelines that scan large amounts of data, sort, group, or transform records run on secondaries rather than competing with primary-only work.
  • Change streams: Cache invalidation, synchronization to systems such as AWS Redshift, and event-driven workloads react to database changes. This work also belongs on secondaries where possible.
  • Ad hoc analysis: Reporting, experiments, and exploratory queries go to the hidden member, isolated from ordinary production traffic.

The primary should concentrate on work only the primary can do. Moving the rest elsewhere preserves its capacity for writes and the reads that need it.

12:5613:08
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

12:56 · section reference included

The next database step is partitioning

Read distribution extends the useful life of a replica set, but it does not remove the limits of keeping the entire dataset on each member and sending writes to one primary. Borucki presents sharding as a planned next step, not an already completed migration. The dataset would be divided among shards, each retaining its own primary and secondaries.

PropertySingle replica setPlanned sharded cluster
Data placementFull dataset on each memberA portion on each shard
ReplicationOne set of replicasReplication within each shard
Write destinationOne primaryThe primary of the relevant shard
Horizontal expansionMore read-serving membersMore shards sharing the dataset

Adding shards introduces more places to store and process data. MongoDB’s balancer redistributes data across them, but the distribution depends on a consequential design choice: the shard key. Borucki explicitly leaves that nontrivial choice outside the talk’s scope. The intended expansion covers CPU, memory, storage, reads, and writes.

16:3816:52
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

16:38 · section reference included

Scale application replicas and the capacity beneath them

At the application layer, the Hub’s HPA configuration responds when CPU or memory rises above its target. Borucki reports that the Hub deployment can scale from 10 to 500 pods depending on traffic. It scales back down as demand drops, reducing the need for manual intervention and permanent overprovisioning.

More desired pods do not guarantee more usable capacity. If the Kubernetes cluster has no room for them, the scheduler leaves them pending. CAST AI supplies the second scaling layer:

  1. HPA increases the deployment’s requested pod count.
  2. Pods remain pending when existing nodes cannot accommodate them.
  3. CAST AI adds nodes.
  4. The Kubernetes scheduler places the pending pods on the new capacity.

Pod scaling changes how many application replicas should run. Node scaling supplies the infrastructure on which those replicas can run.

The next planned change is adoption of KEDA, Kubernetes Event-Driven Autoscaling, to make scaling decisions from application signals such as requests per second and event-loop utilization. A pod can have low CPU utilization while requests accumulate in a queue; resource utilization alone can therefore miss demand that matters to users. The CPU/memory limitation here describes the Hub’s presented HPA configuration, not HPA in general: HPA also supports custom and external metrics, and KEDA integrates with it rather than replacing its underlying control loop.

Kubernetes diagram connects users, a Hub Deployment labeled 10 to 500 pods, KEDA, and horizontal scaling, with panels for application-aware autoscaling and workload signals.
KEDA autoscaling driven by requests and event-loop signals.

The user-facing test of all this machinery is simple: pushing a model, searching the Hub, or downloading a model should work without requiring the user to understand it. The internal architecture can become more elaborate as the catalog grows, while those everyday actions remain straightforward.

18:1918:41
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

18:19 · section reference included

Resources

From the talk

Updates since the talk

Read the complete timestamped transcript
  1. 0:00

    [on hold music] Good afternoon, everyone. I have a question.

  2. 0:19

    How many of you knows Hugging Face? Nice.

  3. 0:27

    How many of you already use Hugging Face?

  4. 0:33

    Amazing. Almost everyone. But I think we still have opportunity to grow our usage. My name is Arek Borucki. I work as machine learning platform and database engineer at Hugging Face.

  5. 0:49

    Today, I would like to walk you through how Hugging Face scaled

  6. 0:57

    infrastructure, and how we ended up serving three million models to developers around the world.

  7. 1:09

    I would like to share architectural decisions we made, challenges we faced, and lessons we learned while scaling one of the fastest growing open source AI communities in the world.

  8. 1:29

    I hope you will enjoy it, and let's get started.

  9. 1:37

    Before I dive into technical details, let's talk about scale.

  10. 1:44

    Today, Hugging Face serves more than fourteen million users, and this number is growing very fast, especially in the last couple of months.

  11. 1:57

    We host three million public models, one million datasets,

  12. 2:07

    ten-- fifty thousand organizations. And not only hobbyists or scientists.

  13. 2:16

    More than thirty percent of Fortune five hundred use Hugging Face as a part of AI workflows.

  14. 2:27

    Just to give you some perspective, three years ago, we had twenty thousand models. Today, three million.

  15. 2:39

    It is around one hundred fifty x increase in just last couple of years.

  16. 2:48

    And this growth is exactly why I'm here today talking about infrastructure decisions that keep the hub healthy at scale.

  17. 3:03

    This is how fast the number of public models is growing on the hub. Every big release like Llama or DeepSeek generated thousands of new models on top,

  18. 3:20

    and our infrastructure needs to handle that. And it is not only models,

  19. 3:28

    also datasets. In twenty twenty-two, we had ten K.

  20. 3:36

    In twenty twenty-four, one hundred K. Less than a year ago, we had five hundred K. Today, one million.

  21. 3:49

    All this data must be stored, indexed, and also must be searchable. And that's the hardest part.

  22. 4:02

    And this is also the reason why we had to rethink our search.

  23. 4:09

    At twenty thousand models, any query is fast, even without an index. Trust me, no one would notice. At three million, same approach breaks.

  24. 4:23

    Imagine what would you do if the hub search would be slow.

  25. 4:30

    You would just leave and go somewhere else, and this is also what user are, are doing. They expect fast, instant results.

  26. 4:39

    With fourteen million users, even one percent is a not small number. It is one hundred and forty thousand of people hitting slow search.

  27. 4:56

    At scale, P99 is much more important than P50, and we are paying a lot of attention to P99.

  28. 5:09

    And that's the reason why we invest in pre-compute tokens,

  29. 5:16

    denormalize, optimize for read, collection in MongoDB, full-text search based on Apache Lucene, Kubernetes autoscaling,

  30. 5:30

    and soon in database sharding. The next slides will show you how.

  31. 5:41

    High-level architecture. When user interact with the Hugging Face Hub, his request flows from the front end to the Hub API.

  32. 5:54

    The hub is running on Kubernetes. Currently, we are using Horizontal Pod Autoscaler.

  33. 6:03

    During spikes, new pods scale up automatically to handle the load and scale back down when traffic drops.

  34. 6:14

    This help us to keep the hub healthy without manual intervention. Next, the request

  35. 6:26

    goes to MongoDB Atlas, which is source of true for our metadata. And there is one point that sometimes surprise people. MongoDB does not store the models themselves.

  36. 6:44

    It stores everything about the models. What does it mean in practice?

  37. 6:52

    In MongoDB, we hold all the metadata, users, repositories, models, data sets, buckets, spaces information, configuration data, billing data, access control, and more.

  38. 7:17

    The actual models artifacts, tokenizer files, card assets, and configuration files are stored separately in cloud object storage, such as AWS S3.

  39. 7:34

    This separation of concern let us scale metadata independently from binary storage and compute independently from both.

  40. 7:46

    We can optimize each component individually for specific workload.

  41. 7:55

    Now let's check how search works in details. For example, someone wants to search the model on the hub, and let's say that's Llama. So someone type Llama into Hugging Face search bar.

  42. 8:12

    His request flows through the hub to an optimized read collection on MongoDB. And this is not our main repo collection when we keep all the data. It's a separate denormalized copy

  43. 8:30

    only for reads and listings. The key information is on the left.

  44. 8:40

    We tokenize model names on insert time, not at query time.

  45. 8:47

    For example, someone wants to publish model meta-llama/llama3.18b.

  46. 8:58

    We split the long model name into small tokens like meta, llama, three dot one, eight b, and we store them in an array in MongoDB document. Next, Atlas Search, which is using Apache Lucene under the hood, use autocomplete to find matching models

  47. 9:23

    instantly. This is example of single document from our model collection. In this example, I'm using findOne method. I want to find model ID meta-llama/llama3.18b.

  48. 9:43

    So that's the model from the previous slide.

  49. 9:48

    And I'm projecting only searchToken array. And we see that all those precomputed tokens are part of this array. So we have meta, llama, three dot one, meta, llama, et cetera.

  50. 10:03

    Next, there must be a query. In the past, we were using classical MongoDB find method on models collection with regex operator.

  51. 10:20

    And this regex operator were searching in search tokens arrays models which are equal to llama.

  52. 10:30

    And then we were set-- sorting results by trending score, which is calculated every five minutes. This is number of downloads and number of, of likes.

  53. 10:43

    It is, as far as I remember, from the last seven days.

  54. 10:48

    This solution was working well as long as data set was small.

  55. 10:55

    Regex doesn't scale well, so when our data set started to grow very quickly, we started to having problems with latency. So we decided to switch to Atlas Search.

  56. 11:11

    That's a feature which is using Apache Lucene under the hood.

  57. 11:18

    So MongoDB doesn't provide in core MongoDB server full-text search. There is additional process, mongot.

  58. 11:29

    Uh, this MongoDB process is a wrapper around Apache Lucene.

  59. 11:37

    For end user, the-- users, this is transparent. You are just using unified MongoDB query API. And

  60. 11:47

    when you use aggregation pi-pipeline together with dollar search operator, MongoDB will know that you would like to search Apache Lucene index.

  61. 12:02

    Obviously, you need to put the name of this index, which is in this scenario, model search.

  62. 12:11

    Auto-complete model equal to Llama, path search tokens,

  63. 12:20

    and we still sort results by trending score. And this solution is much more efficient,

  64. 12:28

    and is so far scale well. So we don't have any more latency issues in our search bar.

  65. 12:41

    First two results returned by previous query. First Meta Llama has trending score thirty-three, second one fourteen.

  66. 12:56

    But Hugging Face Hub is not only search. We have hundreds of different services in Hugging Face which are utilizing, which are using MongoDB.

  67. 13:08

    To handle million of queries, we use seven nodes MongoDB clusters, cluster.

  68. 13:17

    With multiple machines, we can distribute queries across multiple nodes, so no single node become read bottleneck.

  69. 13:29

    This is how it works. Application talk to the MongoDB cluster. All inserts, deletions or updates goes to single primary because only primary can handle them.

  70. 13:43

    However, we are distributing reads across multiple machines.

  71. 13:51

    We also have one analytic hidden node. What does it mean? This me- this node is invisible from application. Mong- MongoDB driver is not routing any queries to this hidden node.

  72. 14:10

    This node is still replicating data from primary, but it's not interacting with, interacting with production traffic. We are connecting directly to this node, and we use him for any kind of

  73. 14:28

    reporting traffic on re- or any kind of really heavy queries.

  74. 14:35

    All secondaries continuously tail the oplog from primary, keeping cluster in sync.

  75. 14:45

    Now let's have a look what actually is running on secondaries. First, all queries which doesn't require the latest data go to secondaries.

  76. 14:58

    Only queries that must have strong consistency stay on primary, and we are paying a lots of attention to this. We are paying lots of attention to the queries which must run on primary.

  77. 15:15

    Second, complex aggregations. Aggregations pipelines that scan large amount of data, sort, group, or transform the data

  78. 15:31

    should not go on primary. They are heavy. Secondaries are better place for them.

  79. 15:38

    Third, change streams. We react to data changes in real-time for several reaso- reasons. For example, cache invalidation, sync to different data store technologies like, for example, AWS Redshift, or for event-driven workloads.

  80. 16:00

    Those kind of operations are also not very light, and they should stay impossible on secondaries. Fourth,

  81. 16:10

    all ad-hoc queries, reporting queries, maybe some experimental queries go to hidden MongoDB replica set member which is isolated from production traffic.

  82. 16:23

    The pattern is simple. Primary should focus on what only primary can do. Anything else can be pushed to different machines.

  83. 16:38

    However, with forty million users, three million models and our grow, soon single MongoDB replica set will not be enough.

  84. 16:52

    The next step is sharding. Sharding means scaling your database horizontally. Instead of putting full dataset on one repli- on one replica set cluster, we are going to cut data into pieces

  85. 17:13

    and put each piece on separate shard. Each shard will have his own replication, primary and secondary. So we will keep replication just multiplied.

  86. 17:26

    The key difference between replica set cluster and sharded cluster is replica set keep full dataset on each node. Sharded cluster keep only part of the data on each shard.

  87. 17:39

    And then if you want to scale horizontally more, you are just adding more shards, and then MongoDB balancer will balance data across all those shards. There is also shard key which must be selected.

  88. 17:53

    This is not trivial operation, but this talk is not about choosing shard key.

  89. 18:00

    This way we are going to scale everything,

  90. 18:04

    CPU, memory, storage, reads and writes Now let's have a look what is going on the hub level.

  91. 18:19

    The hub is running on Kubernetes. S- currently, we see are using Horizontal Pod Autoscaler. When CPU or memory threshold goes above target, Kubernetes adds new pod automatically to handle the spike and scale them back down when traffic drops.

  92. 18:41

    Our deployment, hub deployment can scale from ten to five hundred pods, depends on, on the traffic. This is how we keep the hub healthy without manual interventions and without infrastructure overprovisioning.

  93. 18:59

    So this is also cost-effective solution. However, what happens if Horizontal Pod Autoscaler want to add new pods but Kubernetes does not have free nodes anymore?

  94. 19:17

    This is where second layer comes in. We are using Cast AI for Kubernetes node autoscaling. When pods are pending because there is no capacity and Kubernetes sched- scheduler is not able to schedule them, Cast AI is adding new nodes, and then scheduler is able to schedule those

  95. 19:41

    pods. So we have two layers of scaling. First one is at deployment level, second one is at infrastructure level via Cast AI.

  96. 19:54

    But we are going to migrate Horizontal Pod Autoscaler to KEDA, Kubernetes Event-Driven Autoscaling. The difference,

  97. 20:07

    HPA scale only based on CPU and memory. KEDA scale on real application metrics like request per second or

  98. 20:19

    event loop utilization. It means scaling is driven by actual workload, not by resource utilization only. For example, pod can have low CPU but high request queue, KEDA can see it, HPA not.

  99. 20:43

    The best part of this architecture, you never have to think about it. When you pop-- When you push the model, search the hub, or download the model, it just works.

  100. 20:58

    This is what scaling million models is really about, keeping the user experience simple no matter how complex it gets under the hood.

  101. 21:10

    Thank you very much. It was pleasure for me to be a here today, and I wish nice day for all of you. [audience applauding]

  102. 21:21

    Thank you. [outro music]