TL;DR: The leaderboards rank Python bug-fixing. For TypeScript, React and CSS, pick on context window and tool-call reliability first, parameter count last. On a 24 GB machine
ai/devstral-small-2is the safe default; on 32 GB or moreai/qwen3-coderwins on context. And the 22% figure attached to Qwen3-Coder all over the internet belongs to a different model.
The benchmark everyone quotes is not measuring your job
Ask which local model is best at coding and you will be handed a SWE-bench Verified score. It is a good benchmark. It is 500 manually screened GitHub issues, and an agent passes only when a hidden test suite goes green, which is much harder to game than a function-completion test.
It is also entirely Python.
So when a 24B model scores 68% and you write React, you have learned something real but oblique: that model can navigate an unfamiliar repository, keep track of several files, and produce an edit that applies cleanly. Those skills transfer. What has not been measured is whether it knows that useEffect with a missing dependency array will re-run forever, whether it can write a discriminated union that actually narrows, or whether it reaches for flexbox when the answer is grid.
The benchmarks that would tell you are thin on exactly the models you can run at home:
| Benchmark | Covers your stack? | Local models listed |
|---|---|---|
| SWE-bench Verified | No, Python only | Many |
| Multi-SWE-Bench | Yes, TS and JS included | Six models total |
| Aider Polyglot | Partly, JavaScript not TS | 22, mostly frontier |
| WebDev Arena | Yes, React and TS and Tailwind | Frontier-dominated |
Multi-SWE-Bench is the right benchmark and almost nobody has been run through it. So the honest position is that for TypeScript specifically, you are choosing on proxies. The rest of this article is about picking better proxies than parameter count.
Fix the numbers first
Before comparing anything, one correction, because it has propagated into a dozen "best local model" posts.
You will repeatedly see Qwen3-Coder at 22% on SWE-bench Verified, presented as evidence it is far behind. That score belongs to Qwen3-30B-A3B, the general-purpose model. Qwen3-Coder-30B-A3B-Instruct, which is what docker model pull ai/qwen3-coder actually gives you, sits around 50 to 52% under standard scaffolding. The names differ by one word and the conclusion flips.
With that fixed, the honest scoreboard for the models Docker Hub ships in the ai/ namespace:
| Model | Size | Params | SWE-bench Verified | Native context |
|---|---|---|---|---|
ai/devstral-small-2 | 15.2 GB | 24B dense | ~68% (vendor) | 256k |
ai/glm-4.7-flash | 18.3 GB | 30B MoE, 3B active | ~59% | ~198k |
ai/qwen3-coder | 18.6 GB | 30B MoE, 3B active | ~50-52% | 256k |
ai/gpt-oss | 12.1 GB | 20B MoE | not published for 20B | 128k |
ai/deepcoder-preview | 9.0 GB | 14B dense | not comparable | 64k |
Vendor-reported numbers are vendor-reported. Mistral's 68% for Devstral Small 2 is measured with their own scaffolding, which is a legitimate thing to publish and not the same as an independent run. Treat the column as a ranking hint, not a measurement.
The three things that actually decide it
Context window, and the memory it quietly costs
A React task is almost never one file. Change a component and you touch its props interface, the hook it calls, a test, and a stylesheet. An agent has to hold all of those, plus its own tool schemas, plus whatever it has already read.
This is where parameter count misleads. A 14B model with a 128k window will out-perform a 30B model pinned at 8k on any multi-file change, because the 30B one is working blind. Long native context is the single most predictive spec for agentic frontend work, and it is the one nobody puts in the headline.
The catch is memory. The weights are the number on Docker Hub; the KV cache is extra, it scales with the window you open, and on a 24 GB laptop an 18 GB model plus a wide context is how you discover what swapping feels like. Budget roughly:
- 16 GB machine: 12 GB model, modest context.
ai/gpt-oss, and note it ships a small default you will need to repackage. - 24 GB machine: 15 GB model with room to breathe.
ai/devstral-small-2. - 32 GB and up: 18 GB model with a wide window.
ai/qwen3-coderorai/glm-4.7-flash.
Tool-call reliability, which is invisible until it isn't
Run any of these inside an agent and the failure you actually hit is not bad code. It is the model choosing the wrong tool, or passing the right tool an argument that makes no sense, and the loop grinding.
Worth knowing that under Docker Model Runner the syntax half of this problem is already solved for you: it compiles each tool's JSON Schema into a GBNF grammar and constrains the sampler, so malformed tool JSON is structurally impossible. What remains is judgement, and judgement is exactly what a 4-bit 20B model has least of.
Models fine-tuned for agentic use are markedly better here, and it has little to do with how much React they know. Devstral is explicitly trained for it. ai/qwen3-coder is built around tool use. A general-purpose model of the same size will write comparable JSX and pick the wrong action far more often.
This is also the axis where local models lose to hosted ones most clearly, and it is worth being blunt about it rather than discovering it three hours in.
Quantisation, the tax nobody mentions
Everything in the ai/ namespace runs through llama.cpp and arrives quantised. The size on Docker Hub is not the model, it is a compressed version of it, typically around 4 bits per weight.
For prose that is nearly free. For code it is not, and TypeScript is unusually exposed. Generic types, long identifier chains, and precise import paths are exactly the low-probability token sequences that quantisation degrades first. A 4-bit model that writes fluent-looking React can still hallucinate a member on a type or drop a generic parameter, and it will do it with total confidence.
The practical defence is not a bigger model. It is TypeScript strict mode plus a fast typecheck in the loop, so the compiler catches what the model got wrong before you read it. Local models make a good type system worth more, not less.
What I would actually pull
24 GB machine, general TypeScript and React work: ai/devstral-small-2. It is the best-benchmarked agentic model that fits with room left over, it does not need repackaging for context, and it fails less often on tool calls than anything else in its size class.
32 GB or more, large codebases: ai/qwen3-coder. The MoE architecture means only about 3B parameters are active per token, so it generates fast for its size, and 256k of native context is the thing that makes multi-file React refactors survivable.
16 GB machine: ai/gpt-oss, with realistic expectations. Single components, boilerplate, a stubborn CSS rule. Not agentic refactors.
Do not pull ai/qwen3 or ai/gemma4 for this. They are competent general models and they are not tuned for tool use, which is what the agent loop demands.
Test it yourself, in about fifteen minutes
Published benchmarks will not answer this for your stack, so run a small one. Five prompts, same for every model, graded by whether the output compiles and behaves:
- A typed
useFetch<T>hook with loading, error and abort handling. Grades generics and cleanup. - A discriminated union for a form state machine, plus an exhaustive switch. Grades type narrowing.
- A responsive card grid with CSS grid, no media queries, using
minmaxandauto-fit. Grades modern CSS versus 2018 CSS. - A React component with a deliberately wrong
useEffectdependency array, asked to be fixed and explained. Grades React-specific reasoning. - A three-file change: rename a prop, update the type, update the consumer. Grades tool-call reliability, which is the one that actually separates them.
Task five is the tiebreaker. Tasks one to four most of these models pass. Task five is where you find out which one can be trusted inside an agent, and it is the reason a smaller well-tuned model often beats a larger clever one.
Getting any of them wired into Claude Code is covered in the Docker Hub setup, which also documents the grammar-compilation error that can block the whole thing before you evaluate a single model, and the cost arithmetic that argues against running local as your only model. If you would rather split the work than replace it, the hybrid routing setup puts whichever model you pick here behind the cheap half of every session. Once you have results, hold them to the same standard as anything else an AI writes for you, which is the point of our playbook for testing AI-generated components.
The honest summary
No local model that fits on a laptop is going to replace a hosted frontier model for React work in 2026. The gap is not knowledge of the framework, which they all have adequately. It is sustained agentic behaviour across a long task, and that gap is still large.
What has genuinely changed is the floor. A 15 GB download now writes correct typed hooks and modern CSS, offline, for free, on hardware you already own. Two years ago that was not true. Pick for context and tool reliability, keep the compiler strict, and treat the SWE-bench column as trivia.