#5416: Xet, Buckets, and Auto-Pulling Model Weights

Hugging Face swapped its storage backend to Xet with barely a ripple. So why can't a bucket auto-pull new upstream weights?

Featuring
Listen
0:00
0:00
Episode Details
Episode ID
MWP-5599
Published
Duration
21:44
Audio
Direct link
Pipeline
V5.2
TTS Engine
chatterbox-regular
Script Writing Agent
DeepSeek 4.1 Flash

AI-Generated Content: This podcast is created using AI personas. Please verify any important information independently.

Hugging Face's storage backend swap to Xet is one of the quietest large-scale migrations in recent memory. Xet replaces Git LFS's file-level deduplication with content-defined chunking, breaking files into roughly 64KB chunks whose boundaries are determined by local content rather than fixed offsets. That means a re-quantized model shares most of its chunks with the original, instead of re-uploading forty gigabytes for a few megabytes of change. The Git LFS Bridge kept every existing client working, and a background migration moved 500,000 repositories and 20 petabytes over six months with only a few dozen user complaints.

Storage Buckets are the second half of the story, and they are not repositories with a new name. Buckets are non-versioned, mutable, S3-like object storage with no history, no pull requests, no model cards, and no refs or tags. They share Xet's chunk-level dedup engine but not its semantics. Server-side copy from a repo into a bucket is instant because the bucket just gets a reference to chunks that already exist. The reverse direction, bucket to repo, is on the roadmap but not available yet.

That asymmetry explains why there is no built-in auto-pull. A bucket cannot track an upstream release because it has no native concept of a release at all. No refs, no tags, no commits. Automation has to be built on top with the CLI, Python, or JavaScript APIs, plus external scheduling.

Downloads

Episode Audio

Download the full episode as an MP3 file

Download MP3
Transcript (TXT)

Plain text transcript file

Transcript (PDF)

Formatted PDF with styling

#5416: Xet, Buckets, and Auto-Pulling Model Weights

Corn
Here's the question that's been rattling around my head since I read Daniel's email: can you make a bucket watch a model repo and pull new weights automatically, the way Git users pull upstream?
Herman
And the answer is no. Well... not as a checkbox.
Corn
Right. So let me put Daniel's actual prompt on the table, because it's a good one. He's writing in about Xet, the storage backend Hugging Face swapped in across the Hub. His framing is that model weights are huge, Git was never built for files that big, and Git LFS was the useful middle ground for years. But Xet is interesting because it's tightly coupled to Hugging Face's own bucket product, so you can copy weights straight into your own storage. What he wants to look at is how to use this new storage effectively. And then the real question: if you're integrating other people's models, you want a reliable way to update weights from the upstream lab. Is there a mechanism where a bucket you created for specific weights can be configured to pull automatically whenever new variants of the same release show up?
Herman
Five questions in one paragraph. That's a Daniel special.
Corn
It is. So where do we start?
Herman
With the two nouns. Xet and Buckets. Everything else hangs off those.
Corn
Then start with the scale problem, because that's what forced all of this.
Herman
Hub repos hold files in the range of gigabytes and above. There are terabytes-scale files sitting in repositories right now. And they're binary. Safetensors, Parquet, GGUF. Plain Git is hopeless there, and not for the reason people assume. It's not that Git can't store a big file. It's that a clone retrieves the entire history, every revision, all of it. You'd be downloading four generations of a forty-gigabyte model to get the current one.
Corn
Which is the same reason Parquet took over from row-based formats in data pipelines. The storage model has to match the access pattern, or you pay for it forever.
Herman
Exactly that mismatch. So Git LFS was the workaround. It keeps a small pointer file in Git. SHA256, pointer size, remote file size. The actual bytes live in remote storage, typically S3. The repo stays small, the Git workflows stay fast, and for a long time that was good enough.
Corn
Good enough until it wasn't.
Herman
File-level deduplication. That's the limitation. When a file changes, LFS re-uploads and re-stores the whole file. A forty-gigabyte Safetensors shard where one tensor moved means forty gigabytes of traffic for a few megabytes of difference.
Corn
And that's the sentence that makes Xet make sense.
Herman
Xet was built specifically for this. Chunk-level deduplication, byte-level, smaller uploads, faster downloads, local disk caching. It came out of the XetHub acquisition in August 2024, a Seattle startup. The xet-core library is adapted from xetdata/xet-core, which already had deep Git integration. Deployed January 2025, available on the Hub that March, and default for new users and organizations since May 2025.
Corn
And the second noun.
Herman
Storage Buckets. Launched publicly on the tenth of March this year. S3-like object storage powered by the same Xet engine, but with a completely different contract. Non-versioned and mutable.
Corn
So that's the two nouns. Now let's get into why the old system couldn't keep up, and what LFS was actually doing for us.
Herman
The pointer file is the part people get wrong. It looks like a stub, but it's doing real work. Git tracks the pointer, so your history, your diffs, your branches all behave normally. The pointer says: this file is this big, here's its hash, go fetch it from the LFS server. And for a world where models were uploaded once and downloaded many times, that's a perfectly good design.
Corn
Where does it break?
Herman
Anywhere the file changes often. Fine-tuning runs, quantization sweeps, LoRA merges, anything that produces a new checkpoint from a mostly-identical previous checkpoint. The Hub is full of that. You have mradermacher with forty-two thousand repos, most of them quantizations of the same handful of base models. Under LFS, every one of those is a full copy of the weights.
Corn
Forty-two thousand full copies.
Herman
Not literally, because LFS does deduplicate at the file level. If the bytes are identical, it stores one copy. But the moment a single byte differs, it's a new object. And in practice, quantization changes every weight in the file, so you get almost no reuse.
Corn
Which means the Hub was storing the same model over and over in slightly different numeric precision.
Herman
At petabyte scale. That's the problem Xet was built to solve. Content-defined chunking.
Corn
Define it properly, because this is the mechanism the whole episode rests on.
Herman
The client breaks a file into chunks based on the content itself, not at fixed offsets. It uses gearhash-based boundary detection, so the chunk boundaries are determined by what's in the bytes. Those chunks go into a content-addressed store. On download, the store returns chunk ranges the client asks for, and the client reconstructs the file. The docs put the distinction cleanly: unlike Git LFS, which deduplicates at the file level, Xet-enabled repositories deduplicate at the level of bytes.
Corn
Why does content-defined matter versus just cutting the file into fixed blocks?
Herman
Because fixed blocks are brittle. If you insert a single byte at the front of a file, every fixed-size block after that point shifts by one, and now none of them match the previous version. Every chunk is new. Content-defined boundaries are stable, because the boundary is determined by local content, not by position. Insert bytes at the front, and the chunks after the insertion point still hash the same.
Corn
So a re-quantized model shares almost all of its chunks with the original.
Herman
In the ideal case, yes. Chunk size in practice is around sixty-four kilobytes, per the community write-ups. So a forty-gigabyte shard is roughly six hundred thousand chunks, and a quantization pass might change a fraction of them rather than all of them.
Corn
The TRL delta-weight-sync example is the cleanest illustration of this. Per-step payload on Qwen3-0.6B drops from 1.2 gigabytes to somewhere between twenty and thirty-five megabytes. That's the same principle applied to training checkpoints.
Herman
Same principle, different layer. That's the storage engine. Now the part that explains why nobody noticed the swap.
Corn
The bridge.
Herman
The Git LFS Bridge. It reconstructs Xet files and returns a single presigned URL that mimics the LFS protocol. So any client that doesn't know Xet exists, which is basically every client in early 2025, just sees LFS. It asks for a file, it gets a URL, it downloads. Nothing breaks.
Corn
And uploads?
Herman
Non-Xet uploads land in LFS first, then a background migration moves them to Xet. The migration blog is explicit about the design intent: there would be no hard cut-over from Git LFS to Xet.
Corn
That's the sentence I'd frame. Because the numbers that follow are absurd.
Herman
Five hundred thousand repositories and twenty petabytes migrated in six months. More than a million users on Xet. And the blog's own characterization is that this was perhaps the quietest migration of that magnitude, with only a few dozen GitHub issues, forum threads, and Discord messages across the whole thing.
Corn
Twenty petabytes and a few dozen complaints.
Herman
That's the payoff of keeping the old protocol alive as a compatibility layer. You never force anyone to change their tooling on your schedule. You change the floor underneath them and let them keep walking.
Corn
What did the throughput look like?
Herman
bartowski's migration sustained around thirty-five gigabits per second. mradermacher and RichardErkhov peaked at roughly three hundred gigabits per second while still serving about forty gigabits per second of everyday load. The baseline was just shy of a hundred gigabits per second as of July last year.
Corn
Three hundred gigabits. That's not a migration, that's a firehose.
Herman
Largest single migrations: mradermacher moved 6.1 petabytes across forty-two thousand repos. RichardErkhov 1.7 petabytes across twenty-five thousand. bartowski about five hundred terabytes across two thousand repos. And the batching was a thousand files or five hundred megabytes, whichever came first.
Corn
The batching detail is the one that tells you how careful they were being. Small batches, background, no user-visible pause.
Herman
Right. Which is why the migration story is a good piece of engineering rather than a marketing claim. The bridge plus background migration plus small batches equals a backend swap that most users experienced as nothing at all.
Corn
That's the storage engine. But the question Daniel actually asked is about distribution, and that lives in a different product, Storage Buckets.
Herman
Buckets are where the architectural consequence shows up. And the contract is the opposite of a repository in almost every way that matters.
Corn
Lay out the comparison.
Herman
Repositories have full Git history, pull requests, model and dataset cards, git push and pull. Buckets have none of that. No versioning, overwrite in place, no pull requests, no cards. What they have is S3-like sync, copy, remove, and listing. Both use Xet chunk-level dedup, so the storage engine is shared and the semantics are not.
Corn
So a bucket is not a repo with a different name. It's a different category of object.
Herman
It's a working layer. That's the way to think about it. Buckets live at hf colon slash slash buckets slash username slash my-bucket. The CLI is hf buckets create, sync, cp, rm, list. Python exposes create_bucket, sync_bucket, batch_bucket_files, download_bucket_files, list_bucket_tree. JavaScript support through the hub package from version 2.10.5, Python since huggingface_hub 1.5.0.
Corn
And then the copy that makes Daniel's question interesting.
Herman
Server-side copy. hf buckets cp from a dataset or model repo into a bucket, or the API equivalent copy_files. Only Xet-tracked files are copied server-to-server, and the changelog's framing is that even very large files are copied instantly thanks to chunk-level deduplication. Terabytes in just a few seconds.
Corn
Instant because nothing is actually moving.
Herman
Nothing is moving. The bucket is getting a reference to chunks that already exist in the content-addressed store. That's why it's instant. It requires the same storage region, and small non-Xet files like configs and READMEs get downloaded and re-uploaded the old way, but the weights themselves never travel.
Corn
Now the asymmetry.
Herman
Repo to bucket is instant and server-side. Bucket to repo is not yet available, but is on the roadmap. Those are the docs' words. The launch blog confirms the plan is direct transfers between buckets and repos in both directions.
Corn
So right now a bucket is a working layer, not a publishing layer.
Herman
Which is exactly the constraint that shapes everything Daniel is asking about. Because if you want to distribute weights, you have to publish from a repo. And if you want to consume weights into your own storage, a bucket is the natural landing zone. The flow is one-directional by design at the moment.
Corn
So let's answer the central question directly. Can a bucket be configured to automatically pull new upstream variants?
Herman
No. There is no built-in auto-pull feature. And the reason is structural, not a missing checkbox. Buckets are explicitly non-versioned and mutable. They have no refs, no tags, no commits. There is no native concept of tracking an upstream release, because there is no native concept of a release at all. I went through the storage-buckets docs, the webhooks docs, the jobs docs, the launch blog, the changelog. Nothing.
Corn
So the answer is no.
Herman
The answer is no as a setting. Yes as an architecture. Those are different things and the distinction is the whole episode.
Corn
Then build the architecture.
Herman
Hub Webhooks. You can register a webhook on any repo, including repos you don't own, watching for repo.content events. New commits, new tags, new branches. When something lands, the Hub posts a JSON payload to an endpoint you control.
Corn
And you don't need to be the repo owner.
Herman
You don't. The event scopes include repo, repo.content, repo.config, discussion, discussion.comment. So you can point a webhook at meta-llama slash whatever and get told every time they push.
Corn
Then what?
Herman
Then you run hf buckets cp from that model repo into your bucket. Server-side, effectively instant, because of the chunk reuse. Or you trigger an HF Job to do it. That is the closest analog to the Git distribution paradigm. It's assembled by the user, not configured as a bucket setting.
Corn
So the pattern is: webhook on the upstream repo, copy on the event.
Herman
That's it. And that's reliable, in the sense that it fires on the event. What it isn't is a native feature with a support contract.
Corn
What breaks?
Herman
Your webhook handler is now the reliability layer. The rate limit is a thousand triggers per twenty-four hours per webhook. Payloads are delivered asynchronously with no ordering guarantee. Failing webhooks get auto-suspended. And bucket payloads truncate above ten thousand entries in updatedFiles.
Corn
So retries, idempotency, ordering, all of that becomes your problem.
Herman
All of it. If the upstream lab pushes three commits in ten seconds, you get three payloads in an order nobody promised you. If your endpoint is down, you get suspended rather than queued indefinitely. Those are the properties you inherit.
Corn
There's a detail in the bucket payload worth naming, because it changes how you write the handler.
Herman
For buckets, repo.content fires on files added or deleted, and the payload uses updatedFiles with xetHash and size rather than updatedRefs. And overwriting a file reports as an add.
Corn
Overwriting reports as an add.
Herman
Which means you can't distinguish a new file from a replaced file by the event type. You have to look at the hash.
Corn
That's the kind of detail that eats an afternoon.
Herman
It eats a week if you find it in production.
Corn
What about the scheduled alternative?
Herman
HF Jobs support scheduling and webhook automation, so a cron-style hf buckets sync or cp is possible. davanstrien's blog on using Storage Buckets as a working layer for data pipelines documents exactly this pattern. Buckets as intermediate storage, HF Jobs for the scheduling. It's the same outcome by a different route, and it's arguably more robust if you don't need event-level latency.
Corn
Polling instead of pushing.
Herman
Polling instead of pushing, with the tradeoff that you find out about a new release on your schedule rather than theirs.
Corn
And the third-party evidence.
Herman
backblaze-labs hf-cache-sync syncs the local Hugging Face cache to Backblaze B2 or S3-compatible storage with LRU eviction. The community is building its own sync tooling rather than waiting for a native bucket feature. That's usually a signal.
Corn
A signal of what?
Herman
Either that the native feature is coming, or that a third-party ecosystem is about to form around the gap. Both happen. Sometimes both at once.
Corn
The second-order implication is the part I keep circling.
Herman
Say it.
Corn
Because buckets have no refs and no versioning, reliable update from the upstream lab has to be reconstructed from webhooks plus server-side copy. And the reliability properties you get are the reliability properties of your handler. That's a real gap, not a missing checkbox. It's an architectural fact about what a bucket is.
Herman
It's the same reason Git gave you tags in the first place. Tags are a promise that a name points at a specific set of bytes forever. A bucket can't make that promise, because overwrite-in-place is the whole contract.
Corn
There's a billing tension worth touching too.
Herman
Chunk-level dedup is global. If a chunk exists anywhere on the Hub, it's stored once. But users still see full logical size against their quotas. A community comment on the migration blog noted exactly that, and the author's reply was that dedup is global and billing is based on the logical size of each new object, for predictability and fairness.
Corn
So you pay for the bytes you asked for, not the bytes that were actually new.
Herman
Enterprise is billed on the deduplicated footprint, and there's a headline figure of twelve dollars per terabyte floating around for the standard tier. But for the ordinary user, the quota math is logical size. Which is defensible, and also means the dedup savings don't show up on your bill.
Corn
Defensible and slightly annoying are not mutually exclusive.
Herman
They rarely are.
Corn
There's one more thing in the research that's worth a line, because it tells you where the roadmap sits.
Herman
Wauplin on cold storage tiers. We've discussed such feature internally and we might offer it at some point, but it's not in our short-term roadmap.
Corn
Same posture could apply to native upstream tracking.
Herman
It could. Which is why I'd bet on the community tooling arriving before the setting does.

Hilbert: The tapes were the index.
Corn
What?

Hilbert: The index tapes. I worked at a medical imaging archive for a while. Tapes and a clipboard, that was the job. Every scan was stored under a hash of its contents. Two copies of a file anywhere in that building were the same file, and that was the entire disaster recovery plan. Nobody called it content-addressed storage. It was just how you kept four hundred thousand scans from eating the building.
Herman
So the dedup idea isn't new.

Hilbert: It's not new. The chunking is a good answer to a real problem. I'll give them that. But the interesting part isn't the chunking. It's that they kept the old pointer protocol alive so nobody had to change anything. That's the engineering. Anybody can write a new storage engine. Keeping ten years of tooling working through the swap is the hard part.
Corn
That's the LFS Bridge.

Hilbert: Whatever you call it. The bridge is the achievement. The chunking is arithmetic.
Herman
There's a parallel in the migration numbers. Twenty petabytes and a few dozen complaints. That's the bridge doing its job.

Hilbert: Twenty petabytes. We moved four hundred terabytes over a summer and I still have the tapes in the garage. Box of them. My wife has asked me three times to throw them out.
Corn
Are they readable?

Hilbert: No idea.
Corn
You've never checked.

Hilbert: Never checked.
Herman
So the disaster recovery plan is a box of tapes in a garage that nobody has verified.

Hilbert: The disaster recovery plan was a box of tapes in a garage. The tapes being readable was always somebody else's department. There's a phone call I'm expecting. Won't take it in here.
Corn
The tapes are a problem for another day. Let's leave people with the open questions.
Herman
The one I keep coming back to is the roadmap. If bucket-to-repo transfer ships, and the launch blog says both directions are planned, then the working-layer and publishing-layer split softens. You could promote a bucket back into a versioned repo server-side, and suddenly the asymmetry that shapes every pipeline design right now just... stops being the constraint.
Corn
Which would change the architecture, not just the convenience.
Herman
It would change what a bucket is for. Right now a bucket is a place data lands. If it can be promoted, it becomes a place data stages before it ships.
Corn
And the other open question is whether Hugging Face ever ships a native upstream-tracking setting. The cold storage answer suggests the posture: discussed internally, not in the short-term roadmap.
Herman
The community is already building the missing sync layer. hf-cache-sync exists. That's usually the signal that either a native feature is coming or a third-party ecosystem forms around the gap. Either way, the gap closes. The question is who closes it.
Corn
Thanks to Hilbert Flumingtop for producing. This has been My Weird Prompts, the human-AI collaboration podcast. If you're enjoying the show, a review helps more than you'd think. Everything lives at my weird prompts dot com, including the RSS feed and the archive.
Herman
We'll be back soon.
Corn
See you tomorrow.

This episode was generated with AI assistance. Hosts Herman and Corn are AI personalities.