A .NET library to download files (ONNX models, tokenizers, voice presets, etc.) from Hugging Face Hub repositories with progress reporting, caching, and authentication support.
Get Started
| Product | Versions |
|---|---|
| .NET |
README
π₯ ElBruno.HuggingFace.Downloader
A .NET library and CLI tool to download files (ONNX models, tokenizers, voice presets, etc.) from Hugging Face Hub repositories with progress reporting, caching, and authentication support.
Features
- π¦ Download any file from public or private Hugging Face repositories
- π Rich progress reporting with stages (Checking β Downloading β Validating β Complete)
- π HF_TOKEN authentication for gated/private repositories (env var or explicit)
- π Custom Hub endpoints via
HF_ENDPOINTor downloader options - π Atomic writes using temp files to avoid partial/corrupt downloads
- π Resumable downloads using HTTP range requests for interrupted large files
- π Revision pinning with resolved commit metadata and optional expected commit enforcement
- ποΈ Remote file listing β enumerate files in a repo (models, datasets, spaces) before downloading, no need to know exact paths in advance
- β Required vs optional files β optional files fail silently
- π§Ύ Manifest-based bundles with SHA-256 and size validation
- π HEAD requests to resolve total download size before starting
- βοΈ Skip existing files β only downloads what's missing
- π₯οΈ Cross-platform cache directory helpers (Windows, Linux, macOS)
- π DI-friendly with
IServiceCollectionextension methods - π ILogger integration for structured logging
π¦ NuGet Packages
| Package | Version | Downloads | Description |
|---|---|---|---|
| ElBruno.HuggingFace.Downloader | Core library for downloading files from Hugging Face Hub repositories | ||
| ElBruno.HuggingFace.Downloader.Cli | CLI tool (hfdownload) for managing Hugging Face downloads |
Installation
Library (NuGet)
dotnet add package ElBruno.HuggingFace.Downloader
CLI Tool
dotnet tool install -g ElBruno.HuggingFace.Downloader.Cli
Once installed, use the hfdownload command:
# Download model files
hfdownload download sentence-transformers/all-MiniLM-L6-v2 onnx/model.onnx tokenizer.json
# Download a specific tag into a revision-aware cache directory
hfdownload download sentence-transformers/all-MiniLM-L6-v2 onnx/model.onnx --revision v1.0
# Restart from scratch instead of resuming a preserved partial download
hfdownload download sentence-transformers/all-MiniLM-L6-v2 onnx/model.onnx --no-resume
# Ensure a manifest-defined bundle with integrity validation
hfdownload download --manifest ./phi4-bundle.json -o ./models/phi4
# Check if files exist locally
hfdownload check sentence-transformers/all-MiniLM-L6-v2 onnx/model.onnx tokenizer.json
# List remote files in a repo without knowing filenames up front
hfdownload files sentence-transformers/all-MiniLM-L6-v2
# List remote files in a dataset repo, as JSON
hfdownload files my-org/my-dataset --repo-type dataset --format json
# List cached models
hfdownload list
# Delete a cached model
hfdownload delete sentence-transformers/all-MiniLM-L6-v2
# See all commands
hfdownload --help
See the full CLI Reference for all commands and options.
Quick Start (Library)
1) Download model files
using ElBruno.HuggingFace;
using var downloader = new HuggingFaceDownloader();
var request = new DownloadRequest
{
RepoId = "sentence-transformers/all-MiniLM-L6-v2",
LocalDirectory = "./models/miniLM",
RequiredFiles = ["onnx/model.onnx", "tokenizer.json"],
OptionalFiles = ["tokenizer_config.json", "vocab.txt"],
Revision = "refs/pr/42"
};
await downloader.DownloadFilesAsync(request);
Console.WriteLine($"Resolved commit: {request.ResolvedCommitSha}");
2) Ensure a manifest-based bundle with SHA-256 validation
var manifest = new ModelBundleManifest
{
RepoId = "microsoft/Phi-4-mini-instruct-onnx",
Revision = "main",
Files =
[
new ModelBundleFile
{
Path = "onnx/model.onnx",
Size = 123456789,
Sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
},
new ModelBundleFile
{
Path = "tokenizer.json",
Required = false
}
]
};
var bundle = await downloader.EnsureBundleAsync(manifest, "./models/phi4");
Console.WriteLine(bundle.ResolvedManifestPath);
Manifest-driven bundle downloads validate existing files before reuse, re-download corrupted files, and write a resolved manifest to ./models/phi4/.hf.bundle.resolved.json.
3) Pin a branch or tag to the expected commit
var request = new DownloadRequest
{
RepoId = "my-org/my-model",
LocalDirectory = "./models/pinned",
RequiredFiles = ["model.onnx"],
Revision = "main",
ExpectedCommitSha = "1234567890abcdef1234567890abcdef12345678"
};
await downloader.DownloadFilesAsync(request);
Console.WriteLine(request.ResolvedCommitSha);
4) Check if files are already downloaded
bool ready = downloader.AreFilesAvailable(
["onnx/model.onnx", "tokenizer.json"],
"./models/miniLM");
if (!ready)
{
var missing = downloader.GetMissingFiles(
["onnx/model.onnx", "tokenizer.json"],
"./models/miniLM");
Console.WriteLine($"Missing {missing.Count} files");
}
5) Discover files in a repo before downloading
IReadOnlyList<RepoTreeEntry> entries = await downloader.ListRepoFilesAsync(
"sentence-transformers/all-MiniLM-L6-v2",
RepoType.Model);
foreach (var entry in entries.Where(e => !e.IsDirectory))
Console.WriteLine($"{entry.Path} ({entry.SizeBytes} bytes)");
// Use the discovered paths directly as a download request
await downloader.DownloadFilesAsync(new DownloadRequest
{
RepoId = "sentence-transformers/all-MiniLM-L6-v2",
LocalDirectory = "./models/miniLM",
RequiredFiles = [.. entries.Where(e => !e.IsDirectory).Select(e => e.Path)]
});
6) Track download progress
var progress = new Progress<DownloadProgress>(p =>
{
if (p.Stage == DownloadStage.Downloading)
Console.Write($"\rβ¬οΈ [{p.CurrentFile}] {p.PercentComplete:F0}% (reused {ByteFormatHelper.FormatBytes(p.ResumedBytes)})");
else
Console.WriteLine($"{p.Stage}: {p.Message}");
});
await downloader.DownloadFilesAsync(new DownloadRequest
{
RepoId = "sentence-transformers/all-MiniLM-L6-v2",
LocalDirectory = "./models/miniLM",
RequiredFiles = ["onnx/model.onnx", "tokenizer.json"],
Progress = progress
});
7) Authentication (Private/Gated Repos)
Set the HF_TOKEN environment variable, or pass it explicitly:
var downloader = new HuggingFaceDownloader(new HuggingFaceDownloaderOptions
{
AuthToken = "hf_your_token_here"
});
8) Use a private Hub endpoint
Set the HF_ENDPOINT environment variable, or configure the endpoint explicitly:
var downloader = new HuggingFaceDownloader(new HuggingFaceDownloaderOptions
{
Endpoint = "https://huggingface.internal"
});
The explicit Endpoint takes precedence over HF_ENDPOINT; if neither is set, the downloader uses https://huggingface.co.
9) Dependency Injection
builder.Services.AddHuggingFaceDownloader(options =>
{
options.Timeout = TimeSpan.FromMinutes(60);
});
// Then inject HuggingFaceDownloader in your services
public class MyModelService(HuggingFaceDownloader downloader)
{
public async Task EnsureModelAsync()
{
await downloader.DownloadFilesAsync(new DownloadRequest
{
RepoId = "my-org/my-model",
LocalDirectory = DefaultPathHelper.GetDefaultCacheDirectory("MyApp"),
RequiredFiles = ["model.onnx", "tokenizer.json"]
});
}
}
9) Manage local cache programmatically
var cacheRoot = DefaultPathHelper.GetDefaultCacheDirectory("hfdownload");
var repoId = "sentence-transformers/all-MiniLM-L6-v2";
// List all cached repositories
var cachedRepos = downloader.ListCachedRepos(cacheRoot);
// Check whether required files are cached for one repo
bool isCached = downloader.IsCached(
repoId,
cacheRoot,
["onnx/model.onnx", "tokenizer.json"]);
// Get total cache size for one local repo directory
long size = downloader.GetCachedSize(
Path.Combine(cacheRoot, DefaultPathHelper.SanitizeModelName(repoId)));
// Delete cached files for the repo (safe no-op if not found)
await downloader.DeleteCachedFilesAsync(repoId, cacheRoot);
Direct downloads also write ./models/.../.hf.download.resolved.json so callers can inspect the requested revision and resolved commit later.
Documentation
| Topic | Description |
|---|---|
| Getting Started | Installation, all usage examples, and setup |
| CLI Reference | Complete CLI command reference |
| API Reference | Complete class and method documentation |
| Architecture | Design decisions, data flow, and project structure |
| Publishing | NuGet publishing with GitHub Actions |
Related Projects
- ElBruno.PersonaPlex β Integrates this downloader to auto-download ONNX models for NVIDIA's PersonaPlex-7B-v1 full-duplex speech-to-speech model
Building from Source
git clone https://github.com/elbruno/ElBruno.HuggingFace.Downloader.git
cd ElBruno.HuggingFace.Downloader
dotnet build ElBruno.HuggingFace.Downloader.slnx
dotnet test ElBruno.HuggingFace.Downloader.slnx
Requirements
- .NET 8.0 SDK or later
π€ Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
This project is licensed under the MIT License β see the LICENSE file for details.
π About the Author
Hi! I'm ElBruno π§‘, a passionate developer and content creator exploring AI, .NET, and modern development practices.
Made with β€οΈ by ElBruno
If you like this project, consider following my work across platforms:
- π» Podcast: No Tienen Nombre β Spanish-language episodes on AI, development, and tech culture
- π» Blog: ElBruno.com β Deep dives on embeddings, RAG, .NET, and local AI
- πΊ YouTube: youtube.com/elbruno β Demos, tutorials, and live coding
- π LinkedIn: @elbruno β Professional updates and insights
- π X: @elbruno β Quick tips, releases, and tech news
Downloads by Version
Similar & Alternative Packages
Hand-picked matching NuGet libraries based on tags & ecosystem
Depended On By
Find packages that declare this package as a dependency. NuGet does not provide a reverse-dependency endpoint, so candidates are checked on demand.
Adoption Assessment
Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.
Related Guides & Workflows
Learn how to evaluate, integrate, or audit this package in your .NET project.