MLX vs Ollama on Apple Silicon
We ran both head to head on an M3 Ultra with the same model and workload. They land within measurement noise of each other. That means the real decision is not speed, it is operations. Here is how to choose.
If you run local AI on a Mac, you eventually hit the question: serve models through Ollama, or through MLX (Apple's own machine-learning framework, via mlx_lm.server)? Most comparisons online are one-sided, written by someone who only runs one of them. We run both, on the same hardware, so here is the honest version.
The short answer: on speed, it is a tie. Decide on operations.
The benchmark: within measurement noise
We simulated a realistic 25-turn Claude Code session (each turn appends about 500 tokens of tool output plus a new question) and measured time-to-first-token on identical hardware, an M3 Ultra, with the same 4-bit coding model at the same context length.
| Config | Median TTFT | Mean TTFT | Max TTFT |
|---|---|---|---|
| MLX default (f16 KV cache) | 422ms | 517ms | 1250ms |
| MLX + 8-bit KV cache | 320ms | 328ms | 539ms |
| Ollama (flash attention + 8-bit KV) | 306ms | 326ms | 509ms |
Tuned MLX lands within about 4 percent of Ollama, well inside run-to-run noise. Both stayed flat across the whole session with no latency growth, because both have working prefix caching. These are point-in-time numbers from one model on one machine, not a universal law, but the conclusion has held up repeatedly: once both are tuned, the speeds converge.
The one real gotcha: out-of-the-box MLX is meaningfully slower (422ms vs 306ms here). The fix is the 8-bit KV cache, which closed almost the entire gap. Flash attention is already automatic in MLX's Metal kernels. If you benchmark raw mlx_lm.server against a tuned Ollama and conclude "MLX is slow," you are measuring the missing KV-cache flag, not the framework.
Since speed ties, decide on this
| What you care about | Better pick | Why |
|---|---|---|
| Operational maturity | Ollama | Battle-tested, mature tooling, predictable behavior. |
| Model coverage and updates | Ollama | Huge curated library plus Hugging Face GGUFs; new models land fast. |
| Tool-calling / agent reliability | Ollama | More stable tool-use path across more models. |
| Simple workflow | Ollama | ollama pull, ollama list, and it just runs. |
| Many models hot on one machine | MLX | Each model is an independent process, sidestepping any single-server model cap. |
| Apple-first features | MLX | Speculative decoding, KV-quant flags, vision models tend to land here first. |
| Very large (400B+) models | MLX | Handles the frontier-size class well on an M3 Ultra. |
The rule of thumb: default to Ollama; reach for MLX as a second-tier backend when you need many models resident at once, an MLX-first feature, or the very largest models. Speed will not be your deciding factor, because there is no speed difference to decide on.
You do not have to choose: the herd runs both
This is the part most comparisons miss, because they assume you pick one framework for everything. Ollama Herd runs both backends first-class. You can serve a coding model through mlx_lm.server on the node with the most memory, run general models and embeddings through Ollama elsewhere, and the router treats every backend uniformly behind one endpoint. Your client never knows or cares which framework answered.
So the real answer to "MLX or Ollama?" on a fleet is often both, chosen per model, per node, for the operational reason that fits, not for a speed difference that is not there.
pip install ollama-herd # or: brew install ollama-herd
herd # router; discovers Ollama and MLX nodes alike
Related Reading
- Models tested on Apple Silicon, run through both backends
- How much RAM you need, the sizing math
- Routing Engine, how the herd picks a backend and node