The best local LLM for coding: what to measure before you switch

Every ranked list of local coding models is answering a question with three hidden variables in it: which machine, which task, and which build of the model. Change any one of them and the order changes. That is why two credible articles can put different models first without either being wrong. The practical route is to fix the variables for the machine in front of you, then run a short measurement, and let that pick the model. It takes an afternoon and the answer stays valid for as long as the hardware does.

The question has three variables, not one

Which machine. On Apple silicon, the model and its context share unified memory with everything else running. A 19 GB model on a 16 GB Mac is not slow, it simply does not fit, and what happens instead is offloading to the CPU with a collapse in throughput.

Which task. Autocomplete inside an editor, a one shot refactor of a single file, and an agent that reads a repository and runs commands are three different jobs. The first rewards a small fast model. The third needs tool calling and a large context, and will fail with a model that has neither, regardless of how it scores on code generation benchmarks.

Which build. A model name is not a file. On Ollama's library, devstral:24b is a 14 GB download at its default quantization, 25 GB at q8, and 47 GB at fp16. Those are three different experiences from one name. Benchmarks rarely state which build they measured, which is enough on its own to make cross article comparison unreliable.

None of this means published rankings are useless. It means they narrow a field of forty candidates to five, and the last step belongs on the actual machine.

Memory is the constraint that is not negotiable

Work out the ceiling before reading any more recommendations. The rough sum is the model file size, plus the memory the context allocation takes, plus what macOS and the open applications already hold.

Current Macs make this concrete. A MacBook Air ships with 16 GB, 24 GB or 32 GB of unified memory. A Mac mini offers 16, 24, 32 or 64 GB. A MacBook Pro goes from 16 GB up to 128 GB depending on the chip. None of it is upgradeable after purchase, so the number on the machine is the number for its whole life.

Against that, the download sizes on Ollama's library are unforgiving at the top end. qwen3-coder:30b is 19 GB and qwen3-coder:480b is 290 GB. qwen3-coder-next is 52 GB. gpt-oss:20b is 14 GB and gpt-oss:120b is 65 GB. deepseek-coder-v2:16b is 8.9 GB, and the 236b variant is 133 GB.

The useful conclusion is that on 16 GB and 24 GB machines the choice is already made: the field is models in the 4 GB to 9 GB range, and the remaining decision is which one. At 32 GB, a 19 GB model fits with a modest context. Above 48 GB the field opens up, and the question becomes worth arguing about.

Context length decides more than the model does

This is the setting that gets blamed on the model. Ollama picks a default context from available video memory: under 24 GiB it uses 4k tokens, from 24 to 48 GiB it uses 32k, and at 48 GiB or more it uses 256k. Its own documentation then says that tasks needing large context, naming web search, agents and coding tools specifically, should be set to at least 64000 tokens.

Read those two facts together. On a Mac with 16 GB or 24 GB of unified memory, the default context for a coding agent is 4k tokens, which is roughly one medium source file. An agent given that will read a file, lose the beginning of it, and produce confused edits. Swapping the model changes nothing. Setting OLLAMA_CONTEXT_LENGTH=64000 ollama serve, or moving the slider in the app's settings, changes everything.

The cost is memory, and it is why a smaller model with a usable context often beats a larger model squeezed into 4k. That trade is the single most important one in local coding setups, and it is invisible in every benchmark table, because benchmarks run at whatever context the harness set.

Parallel requests multiply the allocation rather than sharing it. OLLAMA_NUM_PARALLEL defaults to 1, and the documentation states that a 2K context with four parallel requests becomes an 8K context with the memory to match. An editor plugin plus an agent plus a chat window is three callers.

What fits on the Mac you have

Download size on Ollama's library Examples Comfortable from
1 GB to 2 GB qwen3.5:0.8b, deepcoder:1.5b, qwen2.5-coder:3b 16 GB, with room for a large context
4 GB to 7 GB qwen2.5-coder:7b, qwen3.5:9b 16 GB
8 GB to 10 GB deepseek-coder-v2:16b, qwen2.5-coder:14b, deepcoder:14b 24 GB
14 GB gpt-oss:20b, devstral:24b 32 GB
17 GB to 20 GB qwen3.5:27b, qwen2.5-coder:32b, qwen3-coder:30b 32 GB, tight with a large context
24 GB and up qwen3.5:35b, qwen3-coder-next at 52 GB, gpt-oss:120b at 65 GB 64 GB and above

The sizes are from the tag list on each model's page, which shows the file size next to every quantization. Checking there before pulling avoids a 290 GB surprise.

A model labelled for code is not automatically the current answer

There is a pattern in the library worth noticing. The models with coder in the name were, for the most part, released some time ago: the qwen2.5-coder family, deepseek-coder, deepseek-coder-v2 and starcoder2 all date from earlier generations. The general purpose models that carry a tools capability are the ones being updated now.

That matters because of what an agent needs. Completing the next line of a function is a task a code specialised base model does well. Reading a repository, deciding to run a test, calling a tool, and reacting to the output is a different capability, and it depends on tool calling and instruction following rather than on code specific training. A general model with tool calling will often outperform an older code specialised model at that job while losing to it at raw completion.

So the split is by task, not by label. For inline completion, a small code specialised model is a reasonable default. For anything agentic, filter the library by tool support first and treat the coder suffix as irrelevant.

Wiring it into the tool already in use

Testing a model in a chat window and using it inside a coding tool are different experiments, and only the second one answers the real question.

Ollama has a command for this. ollama launch configures and starts an external application against a local model, and the supported targets include Claude Code, Codex, OpenCode, VS Code and Droid. ollama launch claude --model qwen3.5 sets up that pairing in one step, and ollama launch droid --config writes the configuration without starting anything. That is the shortest path from a pulled model to a real task.

For tools without a preset, the OpenAI compatible endpoint covers most of them: point the base URL at http://localhost:11434/v1 and use the local model name. Clients that speak the Anthropic message format take http://localhost:11434 as the base URL and append the rest themselves. LM Studio's equivalent is http://localhost:1234/v1, and its documentation notes that Codex works against it because the /v1/responses endpoint is implemented.

What usually goes wrong at this step is not the wiring. It is that a coding agent sends far more tokens per turn than a chat window does, which is exactly when a 4k default context stops being survivable and when a model that fitted comfortably starts offloading. Test with the agent, at the context length intended for real use, or the measurement describes a setup nobody will use.

Disk is the other thing to plan. Models live under ~/.ollama/models on macOS, and OLLAMA_MODELS moves that directory elsewhere, which matters when three candidates at 19 GB each are being compared on a 512 GB machine. Deleting the losers with ollama rm after testing is part of the process rather than an afterthought.

Build the measurement before choosing the model

Ten tasks from actual work beat any leaderboard, because they encode the languages, the code style and the failure modes that matter locally. Pull them from recent commits and pull requests.

A workable set: add a function to an existing file in the project's style, write a test for something already written, explain an unfamiliar function, find the cause of a failing test, do a rename across three files, convert a data shape, write a shell one liner from a description, produce JSON matching a schema, review a diff, and update documentation for a change. Write the expected outcome for each before running anything.

Grade pass or fail, nothing finer. The temptation is to score out of ten, which produces numbers that cannot be compared across a week of testing. Run the same ten against two or three candidate models with the context length already raised, and the result is usually decisive, because local models fail in obvious ways rather than subtle ones.

Keep the results in one plain text file, with the model tag, the context length and the date on every row. Local models move quickly, and a run from three months ago is a different model under the same name. Without the file, the same afternoon gets spent again the next time a release makes the question feel open.

Two numbers from the server complete the picture. ollama ps prints a PROCESSOR column, and anything other than 100% GPU means part of the model is on the CPU and the timing is not worth recording. In a non streamed API response, eval_count divided by eval_duration gives tokens per second for that call, and load_duration shows whether the model had to be read from disk first. Those come from the machine being used, which is more than any published figure can claim.

What to change first

Before downloading another model, raise the context length to at least 64000 tokens and rerun the task that disappointed. That single change accounts for a large share of the cases where a local model looks incapable. Then write down ten tasks from recent work and run them against what is already installed, so the next download is a decision rather than a guess.

The loop is a terminal, the repository, and a scratch file of results, and it suffers from every window switch. A file manager with the terminal in the same window keeps the folder, the commands and the notes in one place, which is the working shape Atriens was built for.

Frequently asked questions

How much unified memory is needed to run a coding model locally?

Enough for the model file, the context allocation and macOS at the same time. At 16 GB, models in the 4 GB to 7 GB range work with a usable context. At 24 GB, 8 GB to 10 GB models are comfortable. A 19 GB model such as qwen3-coder:30b wants 32 GB or more, because the context allocation is added on top of the file size.

Is a model with coder in its name better for coding?

For inline completion, often yes. For agentic work, not reliably. The code specialised families on Ollama's library are from earlier generations, while the general models carrying tool support are the ones being updated. Reading a repository and running commands depends on tool calling, which is a different capability from code completion.

Why does a local model give worse answers than expected on the same prompt?

Context length is the usual cause. Under 24 GiB of video memory the default is 4k tokens, which truncates anything file sized, and Ollama's documentation recommends at least 64000 tokens for coding tools and agents. Raising it before changing model is the faster diagnostic.

Do published benchmarks transfer to a personal machine?

Partly. They are useful for narrowing a long list, and unreliable for the final choice, because they rarely state the quantization or context length used, and neither matches a given local setup by default. A single model name can mean a 14 GB file or a 47 GB file depending on the build.

Is a bigger model at low quantization better than a smaller one at high quantization?

It depends on the task, and it is cheap to test. Both builds appear in the same tag list with their file sizes, so two downloads and the same ten tasks settle it for the work at hand. What is not in doubt is that neither wins if it has to offload to the CPU, which ollama ps reports directly.

Back to all posts