Today we are announcing swift-huggingface, a new Swift package that provides a complete client for Hugging Face Hub.
You can start using it now as a standalone package and will soon be integrated into swift-transformers as a replacement for the current HubApi implementation.
problem
When we released swift-transformers 1.0 earlier this year, we heard loud and clear from the community:
Downloads were slow and unreliable. Large model files (often several gigabytes) fail prematurely and there is no way to restart them. Developers were resorting to manually downloading models and bundling them with their apps, defeating the purpose of dynamic model loading. There is no shared cache with the Python ecosystem. The Python transformer library stores models in ~/.cache/huggingface/hub. Swift apps are downloaded to different locations with different structures. If you already downloaded your model using the Python CLI, download it again for your Swift app. Authentication is complicated. Where should I get the token from? An environment variable? A file? A keychain? The answer is “it depends” and existing implementations didn’t make the options clear.
Introducing the quick hug face
swift-huggingface is a fundamental rewrite focused on reliability and developer experience. It provides:
Full coverage of the hub API — models, datasets, spaces, collections, discussions, etc. Robust file operations — progress tracking, re-support, graceful error handling Python-compatible caching — sharing downloaded models between Swift and Python clients Flexible authentication — making credential sources explicit TokenProvider pattern OAuth support — first-class support for user-facing apps that need to authenticate users Support for Xet storage backends (coming soon!) — Chunk-based deduplication downloads are significantly faster
Let’s look at some examples.
Flexible authentication with TokenProvider
One of the biggest improvements is how authentication works. The TokenProvider pattern makes it clear where the credentials come from.
import hug face
Let me client = hub client. default
Let me client = hub client(Token provider: .static(“hf_xxx”))
Let me client = hub client(Token provider: .keychain(Service: “com.myapp”account: “hf_token”))
Autodetection follows the same rules as Python’s huggingface_hub library.
HF_TOKEN environment variable HUGGING_FACE_HUB_TOKEN environment variable HF_TOKEN_PATH environment variable (path to token file) $HF_HOME/token file ~/.cache/huggingface/token (standard HF CLI location) ~/.huggingface/token (fallback location)
This means that if you are already logged in with hf auth login, swift-huggingface will automatically find and use that token.
OAuth for user-facing apps
Are you building an app where users sign in with their Hugging Face accounts? swift-huggingface includes a complete OAuth 2.0 implementation.
import hug face
Let me authentication manager = try hug face recognition manager(Client ID: “Your client ID”redirect URL: URL(string: “yourapp://oauth/callback”)!scope: (.openid, .profile, .email), keychainService: “com.yourapp.huggingface”keychain account: “User token”
)
try wait authManager.signIn()
Let me client = hub client(Token provider: .oauth(manager: authManager))
Let me User information = try wait client.whoami()
print(“I signed in as: \(user information.name)”)
The OAuth manager handles keychain token storage, automatic updates, and secure sign-out. You no longer need to manage tokens manually.
reliable downloads
Downloading large models is now easy with proper progress tracking and restart support.
Let me progress = progress(Total number of units: 0)
task {
for wait _ in progress.publisher(for: \.fractionCompleted).values {
print(“download: \(Int(progress.fractionCompleted * 100))%”) } }
Let me File URL = try wait client.downloadFile( location: “model.safetensors”from: “Microsoft/Fi-2”to: destination URL, progress: progress)
If the download is interrupted, you can resume it by:
Let me File URL = try wait client.resumeDownloadFile(resumeData:savedResumeData, to:destinationURL, progress:progress )
If you want to download the entire model repository, downloadSnapshot handles everything.
Let me model directory = try wait client.downloadSnapshot(: “mlx-community/Llama-3.2-1B-Instruct-4bit”destination:cacheDirectory, match:(“*.safe tensor”, “*.json”), progressHandler: { progress in
print(“Downloaded \(Progress.Number of completed units) of \(Progress.Total number of units) file”) } )
The snapshot function tracks each file’s metadata, so subsequent calls download only files that have changed.
Shared cache with Python
Remember the second problem I mentioned earlier? “There is no shared cache with the Python ecosystem.” That is now resolved.
swift-huggingface implements a Python-compatible cache structure that enables seamless sharing between Swift and Python clients.
~/.cache/huggingface/hub/ §── models–deepseek-ai–DeepSeek-V3.2/ │ ├── blob/ │ │ └── # Actual file contents │ §── refs/ │ │ └── main # Contains commit hash │ └── Snapshot/ │ └── / │ └── config.json # symbolic link → ../../blob/
This means:
Download once and use anywhere. If you have already downloaded your model using the hf CLI or Python library, swift-huggingface will automatically find it for you. Content-addressed storage. The file is saved by the ETag in the blob/ directory. If two revisions share the same file, the file is saved only once. Symbolic links for efficiency. The snapshot directory contains symbolic links to blobs to minimize disk usage while maintaining a clean file structure.
Cache locations follow the same environment variable rules as Python.
HF_HUB_CACHE environment variable HF_HOME environment variable + /hub ~/.cache/huggingface/hub (default)
You can also use the cache directly.
Let me cache = hub cache. default
if Let me cached path = cache.cachedFilePath( repository: “Deep Seek-ai/Deep Seek-V3.2”type: .model, revision: “major”file name: “config.json”
) {
Let me data = try data(contentOf: cached path) }
To prevent race conditions when multiple processes access the same cache, swift-huggingface uses file locks (flock(2)).
Before and after
Downloading a model snapshot with the old HubApi looks like this:
Let me hub = hub API()
Let me repository = hub.lipo(ID: “mlx-community/Llama-3.2-1B-Instruct-4bit”)
Let me model directory = try wait Hub.snapshot( from: repository, matches: (“*.safe tensor”, “*.json”) ) { progress in
print(progress.fractionCompleted) }
And this is the same operation with swift-huggingface.
Let me client = hub client. default
Let me model directory = try wait client.downloadSnapshot(: “mlx-community/Llama-3.2-1B-Instruct-4bit”destination:cacheDirectory, match:(“*.safe tensor”, “*.json”), progressHandler: { progress in
print(”\(Progress.Number of completed units)/\(Progress.Total number of units) file”) } )
Although the API is similar, the implementation is completely different. Built on the URLSession download task with proper delegate handling, resume data support, and metadata tracking.
Beyond downloads
But wait, there’s more! swift-huggingface includes a complete Hub client.
Let me model = try wait client.listModels( Filter: “Library:mlx”Sorting: “trend”,limit: 10
)
Let me model = try wait client.getModel(“mlx-community/Llama-3.2-1B-Instruct-4bit”)
print(“download: \(model.download ?? 0)”)
print(“like: \(Model.Like ?? 0)”)
Let me collection = try wait client.listCollections(Owner: “hug face”Sorting: “trend”)
Let me discussion = try wait client.listDiscussions(Type: .model, “Username/My Model”)
That’s not all! swift-huggingface has everything you need to interact with the hugging face inference provider, giving your app instant access to hundreds of machine learning models powered by world-class inference providers.
import hug face
Let me client = inference client. default
Let me response = try wait client.textToImage( model: “black-forest-labs/FLUX.1-schnell”prompt: “Japanese Garden of Cherry Blossoms and Silence”provider: .hfInference, width: 1024height: 1024number of images: 1guidance scale: 7.5numInferenceSteps: 50,seed: 42
)
try response.image.write(to: URL(fileURLWithPath: “Generated.png”))
Check the README for a complete list of everything supported.
what’s next
We are actively working in two areas:
Integration with Swift transformers. A pull request is underway to replace HubApi with swift-huggingface. This provides reliable downloads for everyone using swift-transformers, mlx-swift-lm, and the wider ecosystem. If you manage a Swift-based library or app and need help implementing swift-huggingface, please contact us. We will be happy to assist you.
Downloads are faster with Xet. Adds support for Xet storage backend. This enables chunk-based deduplication and significantly speeds up downloads of large models. More on this in a moment.
try out
Add swift-huggingface to your project.
Dependencies: ( .package(url: “https://github.com/huggingface/swift-huggingface.git”from: “0.4.0”))
We welcome your feedback. If you’re frustrated with model downloads in Swift, try this and let us know your results. Your experience report will help you prioritize where to improve next.
resource
Thank you to the Swift-Transformers community for the feedback that shaped this project, and to everyone who submitted issues and shared their experiences. This is for you. ❤️

