Skip to content
Back to Blog
·8 min read

Using a Hugging Face model in an iOS app

Three ways to put a Hugging Face model in an iOS app: a ready Core ML package, a conversion with coremltools, or MLX Swift for language models. Xcode steps, size, licenses and the privacy angle, with Swift that type-checks.

If a Core ML version of the model already exists on Hugging Face, download the .mlpackage, drag it into your Xcode project, and call the Swift class Xcode writes for it. If the model only exists as PyTorch weights, convert it with coremltools (ct.convert, then save("model.mlpackage")). If it is a language model, look at MLX Swift instead. Before any of that, read the license on the model card, because "downloadable" does not mean "free to ship". I downloaded a real Core ML model from Hugging Face for this guide, generated its Swift class with Apple's coremlcompiler, and compiled the Swift below with Xcode 27.1 (Swift 6.4) against the iOS 18 simulator SDK. The coremltools step comes from Apple's documentation and I did not run it.

Which route for which model

Starting pointRouteWhat you ship
Repo tagged coreml with an .mlpackage (for example the apple/ organization)Download it and add it to XcodeA compiled Core ML model in the app, or downloaded later
Model published as PyTorch or TensorFlow weightsConvert with coremltools, then add to XcodeA model package you produced; check the license allows it
Chat or text-generation language modelMLX Swift (mlx-swift-lm) with a model from the mlx-community orgA Swift package plus a model downloaded at run time

Route 1: a ready Core ML package

Hugging Face model cards carry metadata tags such as coreml, and Apple publishes Core ML versions of several vision models under its own apple/ organization. I picked apple/coreml-FastViT-T8, an image classifier trained on ImageNet-1k. Its card says it has 4.0 million parameters, takes a 256 x 256 image, and the Float16 package is 7.8 MB. The card's own instructions download it with the Hugging Face command line tool:

huggingface-cli download \
  --local-dir models --local-dir-use-symlinks False \
  apple/coreml-FastViT-T8

I fetched the same files with the huggingface_hub Python library instead; the result is the same folder, FastViTT8F16.mlpackage, plus a README.md and a LICENSE file. Check what the repo actually contains before you plan around it: some apple/ repos hold older .mlmodel files instead of packages, for example apple/coreml-resnet-50.

Add it to Xcode

Apple's sample describes the steps: drag the model into the project navigator, and open it in Xcode to see the model type and its expected inputs and outputs. Xcode then writes a Swift interface for the model, its input and its output, and compiles the model into a form optimized for the device, which is what ships in the app bundle.

You can see exactly what Xcode writes without opening Xcode. This command, run on the downloaded package, produced one Swift file:

xcrun coremlcompiler generate FastViTT8F16.mlpackage gen --language Swift

The file defines three classes for this model:

  • FastViTT8F16Input, with an image property (a CVPixelBuffer, 256 by 256) and convenience initializers that take a CGImage or a file URL
  • FastViTT8F16Output, with classLabel (a String) and classLabel_probs (a [String: Double])
  • FastViTT8F16, with load() and prediction(input:) in synchronous, completion handler and async forms

This code uses that generated class. I compiled it together with the generated file using the command from the next section, and it type-checks:

import CoreML
import CoreGraphics

func classify(_ image: CGImage) async throws -> (label: String, probability: Double) {
    let model = try await FastViTT8F16.load()
    let input = try FastViTT8F16Input(imageWith: image)
    let output = try await model.prediction(input: input)
    return (output.classLabel, output.classLabel_probs[output.classLabel] ?? 0)
}

I compiled it but did not run a prediction on a photo, so I have no accuracy result to report. The model card lists a 0.9 percent drop in accuracy against the original PyTorch model for this Float16 version, and inference times it measured (0.79 ms on an iPhone 12 Pro Max, 0.62 ms on an M3 Max, mostly on the Neural Engine). Those are the card's numbers, not mine.

Or load it with MLModel

Apple's docs say that in most cases you can use the wrapper class without touching MLModel, but an app that downloads and compiles a model on the user's device must use the MLModel class directly. In that case you call MLModel.compileModel(at:) on the downloaded file and open the compiled copy. This version type-checks for an iOS 18 target:

import CoreML
import Foundation

func loadModel(packageURL: URL) async throws -> MLModel {
    let compiledURL = try await MLModel.compileModel(at: packageURL)
    let configuration = MLModelConfiguration()
    configuration.computeUnits = .all
    return try await MLModel.load(contentsOf: compiledURL, configuration: configuration)
}

The check, run from the Terminal:

xcrun swiftc -typecheck -parse-as-library \
  -target arm64-apple-ios18.0-simulator \
  -sdk $(xcrun --show-sdk-path --sdk iphonesimulator) load.swift

I also built a small macOS command line tool around the same function and ran it on the downloaded package. It printed the model's description: input image 4 256x256, output classLabel 3 and output classLabel_probs 6 (those numbers are the raw values of Core ML's feature type enum, not sizes). computeUnits = .all lets the system choose the processing unit, including the Neural Engine if the device has one; Apple's docs say .cpuOnly is for apps that may run in the background or do other GPU-heavy work. Apple's guide on downloading models also says Core ML puts compiled models in a temporary location, so save the compiled model somewhere permanent, such as Application Support, if you want to reuse it. It also warns to think about iCloud Backup size for large models.

Route 2: convert with coremltools

When a model has no Core ML version, Apple's coremltools documentation describes two steps: capture the PyTorch model graph with torch.jit.trace (the documented stable path) or torch.export, then convert it. This is the docs' own flow, shown here without my having run it:

import torch
import torchvision
import coremltools as ct

# Load a pre-trained model and put it in evaluation mode.
torch_model = torchvision.models.mobilenet_v2(pretrained=True)
torch_model.eval()

# Trace it with an example input.
example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(torch_model, example_input)

# Convert and save as a model package.
model = ct.convert(
    traced_model,
    inputs=[ct.TensorType(shape=example_input.shape)],
)
model.save("newmodel.mlpackage")

Details from the docs: since Core ML Tools 7.0, convert() produces an ML program by default, and ML programs must be saved as an .mlpackage, not an .mlmodel. The weights and intermediate values are Float16 by default, and you can ask for Float32 with compute_precision=ct.precision.FLOAT32 when Float16 is not precise enough. For image models, the docs point to ImageType inputs instead of the TensorType used above (see their Image Input and Output page). They also say the newer torch.export path covered roughly 70 percent of PyTorch operations as of Core ML Tools 8.0, so a model can fail to convert; keep test inputs from the original model and compare outputs before and after.

Route 3: language models with MLX Swift

Core ML is the right default for vision, audio and classic models. For chat-style language models, The ml-explore organization publishes mlx-swift-lm, a Swift package for building tools and apps with large language models and vision language models. Its README shows how to add it to Package.swift and which products to link, and it can load models from the Hugging Face Hub. The MLX guide covers trying the same models on your Mac first, and the mlx-swift-examples repo has an app that runs on both iOS and macOS and downloads a language model. I have not built an app with it for this guide, so I give no memory or speed figures for iPhone.

Size and memory on the device

I could find no memory table for iPhones in Apple's or Hugging Face's docs, so I will not invent one. What the sources do say:

  • Bundling a model is the simplest way to start, but advanced models take significant storage. Apple suggests lower precision weights (from 32 down to 16 bits, or lower, 1 to 8 bits) through the coremltools utilities.
  • If you still need a smaller download, Apple describes downloading the model after install and compiling it on the device, for example when users need only some of the models your app supports.
  • The coremltools docs have separate sections on palettization, linear quantization and pruning for compressing weights.
  • The model card for FastViT lists two variants, T8 at 7.8 MB and MA36 at 84 MB. Pick the smallest one that meets your quality bar, and test on the oldest device you support.

Check the license before you ship

Hugging Face says a license is set in the model card's metadata and asks you to respect it. Cards differ, and this matters for apps you sell:

  • apple/coreml-resnet-50 is tagged mit.
  • apple/coreml-FastViT-T8 is tagged other, with license_name: apple-ascl and a LICENSE file in the repo. Its card says to observe the original license. "Other" means you must read the file; I did not interpret it for you.
  • A converted model is a derived copy, so the original model's terms follow it, and so do the terms of its training data, if the card lists any.

Write down the license, the model's repo URL and the commit you downloaded, and keep them with your release notes.

What this means for App Review and privacy

Apple's App Privacy Details page defines "collect" as transmitting data off the device in a way that lets you or your partners access it for longer than needed to service the request in real time. It also says data processed only on the device is not "collected" and does not need to be disclosed in your App Store Connect answers. So an on-device model that works on a photo and never sends it anywhere can keep that photo out of your data collection answers. Three cautions:

  • The rule covers data that stays on the device. If your app also sends the photo, the result or any usage data to a server or a third-party SDK, answer for that.
  • Downloading a model at run time is a network request. It sends the request itself, such as an IP address, so look at how you host it and what your host keeps.
  • A privacy policy URL is still required for every app, even one that collects nothing. See Does my iOS app need a privacy policy? for the details, and describe in plain words what the model does with the user's input.

Clean up

All files for this guide lived in a scratch folder: the model (7.8 MB), the generated Swift file and a compiled copy. The whole folder was 16 MB, and nothing was added to a project.

Sources

All read on 2 November 2026.

Written by

Building local-first Mac & iOS productivity apps at Obelisk Club. About the author →