{"slug": "why-typescript-7-0-was-rewritten-in-go", "title": "Why TypeScript 7.0 Was Rewritten in Go", "summary": "Microsoft's TypeScript team rewrote the TypeScript 7.0 compiler and tools in Go, achieving roughly an order of magnitude improvement in build times. The decision reflects Go's design for readability and maintainability at scale, which aligns with the needs of AI-assisted and agentic development where code is read more than written.", "body_md": "[spf13 Google -->](/p/spf13-google/)\n\nI’m leaving my role as the Product Lead for the Go Language at Google. I’m super proud of …\n\nOver the last year, the team that invented TypeScript [ported the TypeScript compiler and tools to Go](https://devblogs.microsoft.com/typescript/typescript-native-port/). Not Rust. Not C++. [Go](https://go.dev). Microsoft’s numbers show build times improving by roughly an order of magnitude in the Go-based TypeScript 7.0.\n\nIn the age of AI-assisted development, one of the largest JavaScript/TypeScript organizations on earth chose Go for its flagship tool.\n\nThat shouldn’t be surprising. Go was built on a bet: optimize for the reader, not the writer, in exchange for less code to misread. LLMs read code more than any human ever could, and as they write a growing share of it, humans become even more reader-heavy. Agentic development is the most extreme test yet of the goal Go was built for: readability, maintainability, long-term correctness at scale.\n\nThe conventional argument for Python and TypeScript in the AI era is strong on the surface. Python has PyTorch, LangChain, and the ML ecosystem. TypeScript has the web and a vast developer pool. LLMs trained on mountains of both write them fluently, confidently, and fast.\n\nPython and JavaScript were designed as scripting languages: fast to write, forgiving, dynamic. TypeScript adds structure on top, but it’s a compile-time overlay: types are erased at runtime, so none of TypeScript’s guarantees survive execution. TypeScript hasn’t displaced JavaScript so much as grown alongside it: [GitHub’s 2025 Octoverse report](https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/) has TypeScript overtaking Python and JavaScript by monthly contributors, but JavaScript still generated nearly double the new repositories over the same 12 months, and GitHub’s own summary is blunt: “JavaScript is still massive,” and the combined “JavaScript/TypeScript ecosystem still accounts for more overall activity than Python alone.” Agentic systems aren’t scripts, though; they’re services, pipelines, CLIs, and distributed systems running in production for years, and all three languages fight that design at every step: complexity management, dependency isolation, deployment, runtime safety.\n\nGo was designed as a systems language for large, long-lived software, and the industry is converging on exactly that category: compiled, safe, built to run for years, not scripted for an afternoon. The most exciting thing happening in TypeScript right now is its port to Go. The most exciting things happening in the Python world are mostly happening in Rust: [Pydantic](https://github.com/pydantic/pydantic-core)’s validation core is Rust, [Polars](https://pola.rs/) is Rust, [HuggingFace tokenizers](https://github.com/huggingface/tokenizers) is Rust, and Astral’s [ uv](https://docs.astral.sh/uv/) is Rust too.\n\nGo’s share of that shift looks different but is just as telling: it’s the default choice for the infrastructure the current wave of agentic tools is built on. [Ollama](https://github.com/ollama/ollama), the standard way to run local models, is Go. [Weaviate](https://github.com/weaviate/weaviate), the vector database behind countless RAG and agent-memory stacks, is Go. [Temporal](https://github.com/temporalio/temporal), the durable-execution engine teams use to orchestrate long-running agent workflows, is Go. Charm’s [Crush](https://github.com/charmbracelet/crush), a beautiful AI coding agent CLI in the same category as Google’s [Antigravity](https://antigravity.google/), is Go too. Even [GitHub’s own MCP server](https://github.com/github/github-mcp-server), the reference implementation for connecting AI agents to GitHub, is Go.\n\nIn a development loop, the question isn’t “which language is easiest to write?” It’s “which is easiest to write, review, and ship?” Agentic development multiplies that question. A machine now asks it hundreds of times a day.\n\nAn agentic coding loop looks like this: implement → build → test → analyze failure → self-correct → repeat. A human developer runs this loop maybe a dozen times per hour; an autonomous agent runs it dozens of times per *task*: what [Anthropic’s guidance on coding agents](https://www.anthropic.com/engineering/building-effective-agents) describes as systems that “iterate on solutions using test results as feedback.” That frequency changes the economics of language choice.\n\nWes McKinney named this shift in his essay on [agent ergonomics](https://wesmckinney.com/blog/agent-ergonomics/): once an agent is doing the coding, fast compile-test loops, frictionless distribution, and deterministic builds matter more than whether a language is pleasant for humans to type. He didn’t just write about it. [Roborev](https://github.com/kenn-io/roborev), his continuous background code-review tool for AI coding agents, is built in Go.\n\nGo solves four compounding problems that most engineers don’t notice, because they’re so used to the friction they no longer see it. Each one is paid for in the same currency: developer time and focus, agent iterations, and API dollars spent correcting what the language let through. Let’s walk through these problems in turn:\n\nA several-minute build is routine for large Rust or C++ projects: a minor break for a human, but hours of wasted cycles for an agent running 50 iterations on a feature. Go compiles almost instantly, keeping the loop tight.\n\nPython’s `pip`\n\nstill doesn’t guarantee deterministic installs by default, and version conflicts across machines remain common even with virtual environments. Node’s `npm`\n\nactually handles conflicting transitive dependencies well: nested `node_modules`\n\ncan hold multiple versions of the same package side by side, and `package-lock.json`\n\nplus `npm ci`\n\nmake installs far more reproducible than they used to be. Where npm still gets stuck is peer dependencies, where conflicting requirements throw `ERESOLVE`\n\nerrors that need manual untangling. That version flexibility costs deep, duplicated dependency trees that bloat `node_modules`\n\nand inflate the surface area an agent has to reason about. Both ecosystems also let arbitrary code execute at install time (`setup.py`\n\n, `postinstall`\n\nscripts), a real supply-chain risk that’s bitten each more than once. Go takes a different approach by default: `go.sum`\n\npins exact checksums, a single version of each module is selected deterministically for the whole build, and there’s no install-time code-execution hook for a compromised dependency to exploit. For an agent generating and deploying continuously, that’s less version drift and a smaller attack surface.\n\nPython’s type hints and TypeScript’s type system can catch real mistakes before runtime, when tools like `mypy`\n\n, `pyright`\n\n, or `tsc`\n\nrun as part of the loop. But both come with an asterisk: Python’s typing remains optional and unevenly adopted, even as tools like Pydantic push teams toward it, and TypeScript’s guarantees are erased at runtime, with `any`\n\na sanctioned, zero-cost escape hatch whenever code hits friction. That’s exactly the incentive an agent under time and token pressure responds to: reaching for `any`\n\nto make something compile costs nothing in the moment, whatever the wider ecosystem’s norms are.\n\nJesse Vincent, who builds the [Superpowers](https://blog.fsck.com/) agent orchestration framework, has documented what happens when that opt-out exists: agents rationalize their way around rules. In one now-infamous [incident](https://blog.fsck.com/2026/04/30/that-time-it-tried-to-delete-all-my-tests/), an AI agent in his environment deleted test files to make failing tests disappear: internally consistent logic, since tests that don’t exist can’t fail. His insight, in his own [words](https://blog.fsck.com/2026/04/07/rules-and-gates/): “A rule has an opt-out path (I can rationalize ‘I’ll do it after this one thing’). A gate doesn’t — the next action is blocked until the gate condition is met.”\n\nGo has no such opt-out. Every line is checked at compile time, by construction, with no equivalent of `any`\n\nto bypass it. The compiler is the gate. When a mistake slips through in Python or TypeScript, it tends to surface at runtime, often after the agent has built more work on top of it, and by then it has compound interest in context and API calls spent. In Go, the same error is caught immediately at compile time, before the agent runs anything. The correction is cheap and local. The difference shows in the code itself:\n\n```\n// Go: compile-time error — caught before the agent runs anything\nfunc ProcessData(data interface{}) int {\n    return data + 1 // error: invalid operation: data + 1 (mismatched types interface{} and int)\n}\n# Python: runtime error — agent wastes iterations before discovering the mistake\ndef process_data(data):\n    return data + 1  # no error; error only surfaces at runtime when data is actually called\n\n# Agent runs it, builds on it, then:\nprocess_data({\"key\": \"value\"})  # TypeError: unsupported operand type(s) for +: 'dict' and 'int'\n```\n\nPython’s ergonomic advantage is a disadvantage here: the more forgiving the language, the more mistakes an agent can make before getting caught, burning context and API calls along the way. The same gap shows up in [code review](/p/the-maintainers-dilemma/), now that both sides are often AI: a reviewing agent can see what Python or JavaScript code says but not reliably what it does, since metaclasses and prototype chains hide behavior a static read can’t catch. Go closes that gap the same way it closes the authoring gap: a function name means one thing, method dispatch is by name alone, and there’s no hidden control flow to obscure a bug from either side of the review. Go’s types aren’t a layer added on top; they’re the language itself, covering 100% of the code by construction.\n\nThis may be the largest of the four. Go’s [compatibility promise](https://go.dev/doc/go1compat) means code written for Go 1.0 in 2012 still compiles and runs correctly today. The language and standard library only add; they essentially never break what already worked. Nothing in the Node ecosystem offers that guarantee. Major frameworks routinely break compatibility with their own prior versions: [Svelte 5’s runes](https://svelte.dev/docs/svelte/what-are-runes) are a different reactivity model than Svelte 4, Vue 3 required rewriting Vue 2’s reactivity model from scratch, and React’s evolution from class components to hooks to server components has left multiple incompatible eras of “how React code looks” in active circulation. Ask which Svelte or Vue version a piece of code targets and you’re really asking whether it runs at all. Python isn’t immune; the decade-long Python 2 to 3 migration is its own cautionary tale. But Node’s churn is faster and more constant.\n\nThat churn is a specific, compounding problem for agents. An agent’s working knowledge of an ecosystem is a snapshot frozen at training time, and in a fast-churning ecosystem that snapshot goes stale, producing code that looks plausible but targets an API surface already reworked or deprecated. In Go, a training snapshot from years ago is still correct today. In practice, that means an agent can rely on what it already knows instead of re-verifying its assumptions on every task.\n\nDave Rensin, Distinguished Engineer at Google, captured the compounding risk while [building a 100,000-user internal tool with AI agents](https://drensin.medium.com/elephants-goldfish-and-the-new-golden-age-of-software-engineering-c33641a48874): “If we aren’t careful, we aren’t just writing code faster. We are mass-producing our mistakes.” Go’s structure (static types, explicit imports, no magic) is built-in friction that keeps agents from producing slop at scale by making bad code harder to write.\n\nAt PayPal, [a team shared with me an experience](https://go.dev/solutions/paypal) where a custom C++ database was powerful and correct, but the team had stopped growing: every hire spent months learning the codebase, and most engineering capacity went to maintenance. About six months later, with roughly ten engineers, a Go rewrite outperformed the C++ system in production and cost far less to maintain. Go isn’t faster than C++, so what happened? The bottleneck was never the code’s speed. It was the team’s ability to reason about, maintain, and extend it. Realized performance beats theoretical performance, the same trade agentic teams are making today, just compressed into a much shorter cycle.\n\nRust and Go are complementary and [typically occupy different use cases](/p/rust-vs-go-better-together/) and both have a place in agentic development, but Rust is a specialized tool rather than the default.\n\nRust shares real strengths with Go: memory safety, static typing, no hidden runtime magic. But the two diverge exactly where agentic development is least forgiving. Compile times run far longer, as the build-time problem above illustrates, and the expressiveness behind Rust’s safety guarantees (lifetimes, trait bounds, the borrow checker) costs the single-obvious-way readability Go guarantees by design. Worse, Rust code is markedly harder to refactor once written. Refactorability is the property agentic development leans on hardest, since an agent, not a human, now does that rework and agents are far less capable of reasoning about code than humans and require far more refactoring to get it right. Rust’s safety guarantees are a net positive for humans, but a net negative for agents: the more complex the language, the more likely an agent is to misread it and produce a bug that compounds over iterations.\n\nRust is a lovely language with many strengths. Rust’s zero-cost C ABI bindings, via tools like PyO3 and maturin, make it unusually easy to drop a compiled Rust core underneath a Python package, which is why pydantic, Polars, and HuggingFace tokenizers chose it. Go has historically been the weaker fit here, since cgo added real overhead to that kind of embedding. While Go is closing that gap: [Go 1.26 cut the baseline overhead of cgo calls by about 30%](https://go.dev/doc/go1.26#cgo), Rust remains the better choice for a lot of use cases. For agentic development, though, the tradeoff is clear: Go’s simplicity and readability make it the default choice for the systems layer that agents increasingly run on, while Rust is a specialized tool for when its guarantees are worth the cost.\n\nEverything above is a cost multiplied by iteration count. Context is the constant cost of Agentic work and more of it doesn’t mean better.\n\nThe assumption behind “just use a bigger context window” is that a model reasons over its 200K or 1M tokens uniformly. [Chroma’s 2025 study across 18 leading LLMs](https://www.trychroma.com/research/context-rot) (GPT-4.1, Claude 4, Gemini 2.5, Qwen3) tested that directly, holding task difficulty constant and varying only input length, and found the assumption false: performance degrades as input grows, even on trivial tasks. The biggest driver is what the researchers call distractors: content topically related to what the model needs but not the answer. One distractor measurably hurts accuracy; four compound the damage. Instead of trying to grow the context window, the far better and more economical approach is to reduce the input.\n\nA class hierarchy, a mixin chain, a decorator stack: that’s a field of distractors to an agent tracing a bug. A `super()`\n\ncall resolving through diamond inheritance, a metaclass rewriting behavior at runtime, an override buried three classes up: none of it is the logic the agent needs, but the agent still has to load it, weigh it, and rule it out, inside the same window where its reasoning is already degrading. That’s why agents confidently ship code that ignores an inherited override or calls the wrong mixin’s method.\n\nGo’s design is minimal and explicit. What a file needs lives in that file and its direct imports: no inheritance chains, no mixins pulled in from six directories away, no metaclass rewriting method resolution at runtime. A function name means one thing, and the compiler enforces it. The tokens Go code needs are almost entirely relevant tokens.\n\nThat has a second effect beyond accuracy: it lowers the model a task requires. A bug that fits in 20,000 clean tokens doesn’t need the same frontier reasoning as one buried in 150,000 tokens of framework noise. Simpler, lower-distractor code is easier for a model to get right, which means smaller, cheaper, even local models can write working Go where they’d fail on the Python or Java or Rust or TypeScript/JavaScript equivalent.\n\nThis matters even more when the AI companies stop subsidizing their costs, which we’ve already seen begin. A language whose code stays simple enough for a modest model to handle correctly has a cost structure that survives that subsidy going away. The same property pays twice: what lets a smaller model write the code correctly is what lets a human reviewer read it quickly, since neither side has anything hidden left to re-derive.\n\nBeyond even this, it’s more likely to get the code right the first time, which means fewer iterations, fewer API calls, and less context burned and more time the model can spend on tasks without humans needing to intervene.\n\nContext efficiency is the sharpest form of the same bet Go made in 2009: optimize for the reader, human or machine, over the writer.\n\n`gofmt`\n\nships with Go and runs across the community’s code. Every Go file (human-written, machine-generated, decades old, or written by an agent this morning) looks structurally identical.\n\nSimon Willison, who has spent considerable time building AI-assisted Go tools, [observed this directly](https://simonwillison.net/2026/Feb/4/distributing-go-binaries/): “I’m enjoying how there’s generally one obvious way to do things and the resulting code is boring and readable—and something that LLMs are very competent at writing.”\n\nWhen every Go file looks the same, an agent can be *seeded* before it starts working. Point it at Go’s standard library (`encoding/json`\n\n, `net/http`\n\n, `io`\n\n) and it immediately produces idiomatic, production-quality code, with no guessing about `black`\n\nversus `yapf`\n\nor `isort`\n\nversus `ruff`\n\n. Drop in something like [go-skills](https://github.com/spf13/go-skills) and the seeding gets more direct still, since the agent now has explicit, reusable guidance on writing idiomatic Go rather than inferring conventions from scattered examples. For code review, human or AI, attention goes entirely to logic instead of formatting noise.\n\nMost language comparisons focus on authoring: how fast can you write code? But the software development lifecycle doesn’t end there: build, test, deploy, debug, maintain. In an agentic workflow, every one of those steps runs at machine frequency.\n\nOver the past decade, Go’s ecosystem evolved from a language into a complete SDLC platform: fuzzing became built-in, vulnerability management matured with `govulncheck`\n\n, workspace mode unified monorepo development, and module proxies reduced version conflicts. None of this required reaching outside the Go ecosystem.\n\nDependencies are handled by `go mod tidy`\n\n, deterministic and identical on laptops, CI, and containers, unlike `pip`\n\nor `npm`\n\n, where every resolution failure is an iteration lost. Testing needs nothing beyond `go test ./...`\n\n: no framework decision, no fixtures to configure. Drop a `_test.go`\n\nfile next to the package, write a `Test`\n\n-prefixed function, run one command. For an agent enforcing test-driven development, that reliability makes the gate deterministic in a way Python’s fixture sprawl doesn’t. Compilation stays fast thanks to precise dependency graphs, a direct multiplier on iteration throughput. And deployment is just `go build`\n\n: a single, self-contained binary with zero runtime dependencies, no interpreter versioning, no container startup time. Copy the binary and run it.\n\nThese advantages don’t add linearly, they compound. Faster loops at every step of the cycle mean more iterations per hour, lower API costs, and more reliable outcomes.\n\nThe point of this article was never “replace Python” or “replace TypeScript.” Betting everything on a single language for every layer of a stack is the same mistake no matter which language wins. The real question is narrower: for the systems, services, and infrastructure layer that agentic workflows increasingly run on, which language fits best? In 2026, that’s Go more often than not because it fits that layer unusually well.\n\nPython’s ML ecosystem (PyTorch, LangChain, Transformers) isn’t going anywhere, and it shouldn’t. For training models and running inference, Python is the answer. Go doesn’t compete there. It complements it.\n\nGo can run underneath Python just as easily as beside it. Simon Willison built a tool called [ go-to-wheel](https://simonwillison.net/2026/Feb/4/distributing-go-binaries/) that packages compiled Go binaries as Python wheels distributed on PyPI. Any Go binary becomes a standard\n\n`pip install`\n\nor a `uvx`\n\none-liner. His own `sqlite-scanner`\n\n`uvx sqlite-scanner`\n\n. Python orchestrates; Go executes the high-performance work underneath.Armin Ronacher, creator of Flask, made a [parallel observation](https://lucumr.pocoo.org/2026/2/9/a-language-for-agents/): “The biggest reason new languages might work is that the cost of coding is going down dramatically. The result is the breadth of an ecosystem matters less.” When porting a library costs 45 minutes and $60 in API costs (his own experience porting MiniJinja from Rust to Go), the lock-in argument for any single ecosystem weakens every month. You don’t have to choose between Go’s structural advantages and Python’s ecosystem; you can have both.\n\nGo was designed to lower the total cost of software at scale, exactly the problem agentic development amplifies to the breaking point. Every property that made Go good for human-sized teams makes it well suited to machines running thousands of iterations per day.\n\nNone of this makes Go the only language worth using. Python still owns the ML ecosystem, and there are real reasons to reach for Rust, TypeScript, or something else for a given task. The practical heuristic is narrower than “one language to rule them all”: treat Go as your default for the systems, services, and infrastructure layer of agentic development, and require a specific reason to reach for something else. When starting a new service, CLI, or system, ask “why *not* Go?” If you can name a compelling reason (a critical library that doesn’t exist, a performance profile Go can’t meet, a team investment so deep migration costs exceed savings), make that case. If you can’t, Go is very likely the right default.\n\nEvery percentage point lost to slower builds, flaky dependencies, or runtime surprises is API cost. As agentic workloads scale through 2026, language choice may be the single biggest lever on that cost. Teams that remove this friction early will iterate cheaper and faster than the teams still paying for it.", "url": "https://wpnews.pro/news/why-typescript-7-0-was-rewritten-in-go", "canonical_source": "https://spf13.com/p/go-the-agentic-language/", "published_at": "2026-07-07 20:40:06+00:00", "updated_at": "2026-07-07 21:00:01.747955+00:00", "lang": "en", "topics": ["large-language-models", "developer-tools", "ai-agents"], "entities": ["Microsoft", "TypeScript", "Go", "Google", "GitHub", "Ollama", "Weaviate", "Temporal"], "alternates": {"html": "https://wpnews.pro/news/why-typescript-7-0-was-rewritten-in-go", "markdown": "https://wpnews.pro/news/why-typescript-7-0-was-rewritten-in-go.md", "text": "https://wpnews.pro/news/why-typescript-7-0-was-rewritten-in-go.txt", "jsonld": "https://wpnews.pro/news/why-typescript-7-0-was-rewritten-in-go.jsonld"}}