Rust, Python, TypeScript, and the dark horse
In Rust, Python, and TypeScript: the new trifecta, Niko Matsakis argues that Rust, Python and TypeScript will dominate the coming years.
His argument boils down to this: AI coding reduces tribalism and language choice becomes a purer function of technical merits.
He concludes that in this new world, three dominant languages emerge - Rust (the default), Python (the choice for ML) and TypeScript (the choice for web apps).
This trio resonates with me and I’d pick the same for the trifecta. But the argument leaves perhaps the largest segment of software engineering without a clear owner - the boring backend. All three are capable general purpose languages with strong backend ecosystems. Yet, they leave enough to be desired that I wouldn’t crown any of them as the boring backend default.
The unclaimed backend
Rust is currently held back by the ecosystem.
The most notable gap is the lack of good ways to talk to a database.
ORMs are lagging behind other ecosystems (and perhaps the nature of the language itself makes it hard to catch up?),
and sqlx is rough once you need complex dynamic queries.
But other areas also show gaps - from support for enterprise patterns
(dependency injection, batch processing, actor frameworks, etc.)
to staples of basic web development (e.g. OpenAPI support in the axum world).
It can be a brilliant language in carefully chosen cases where these downsides don’t bite too hard or the team has capacity to fill the gaps. That said, it remains too hit and miss to be a real default.
TypeScript’s only real edge is sharing a language with the frontend. This has two aspects: code sharing and language familiarity for full stack teams. The former is real, but OpenAPI codegen addresses some of it. The latter is evaporating in a world where LLMs do the coding (a key argument of the original article: you pick what’s technically the best, not what you know).
You pay an unnecessarily high cost for these thinning benefits.
The type system is excellent, but it prioritises ergonomics over soundness,
and much of the ecosystem is types bolted onto JavaScript libraries.
An as User assertion compiles to nothing.
Your data is whatever shape the network says it is,
and mismatches surface deep in your program instead of at the boundary.
The ecosystem’s answer is a cottage industry of validation libraries, like zod.
npm is an abyss of ever-changing hype, breaking changes and supply chain attacks.
Then there’s Node’s hard ceiling: CPU-heavy workloads.
Of course, you can just offload those to a separate service,
but then you pay the two-language and microservices tax, more on this later.
As for Python, it will undoubtedly stay dominant in the era of AI coding. But it will be limited to ML and exploratory coding, not just by humans but by agents whenever they need to execute ad-hoc code.
For traditional software engineering, however, Python is increasingly
a poor choice. What makes it great for humans - readability and conciseness -
doesn’t work so well for LLMs favouring explicitness and correctness.
Python’s type hints are a weak guarantee compared to languages designed
to be statically typed from the get-go. uv is a great package manager
modelled after Cargo but it can only do so much due to the structural
issues of virtual environments. Bundling and deployment are a pain compared
to compiled languages.
So what language will claim the boring backend? My contrarian bet is C#.
The .NET you remember is gone
Since the initial release of .NET Core in 2016, the rate at which the platform
has been evolving and modernising is mental.
Long gone are the days of Windows deployments, verbose .csproj files,
enterprise boilerplate everywhere.
The modern stack is a dockerised Minimal API on Linux, EF Core over Postgres,
OpenAPI specs (v3.1, soon v3.2 with .NET 11) generating React Query types for the frontend.
Concise as FastAPI, and EF Core is the only ORM I’ve ever actually enjoyed, and I’m pretty anti-ORM.
If a modern .NET codebase looks an overengineered mess, that’s by choice
rather than something the platform prescribes.
The attitude has changed as much as the tooling.
The whole platform is MIT-licensed and developed in the open, Linux is the primary
deployment target, and every release sheds a little more of the old enterprise ceremony.
It just takes a bare .cs file with dotnet run to print hello world, as it should.
When a hot path does show up, you’re not boxed in the way you are on Node.
Structs give you control over memory layout, Span<T> lets you write allocation-free
code over stack or native memory, and hardware intrinsics are there when you genuinely need SIMD.
It’s not quite Rust, but it’s surprisingly close, and it’s the same language as the rest of your backend.
Technically, modern .NET is an incredibly solid platform held back by its history and negative perception.
What LLMs actually want from a language
Models have seen more TypeScript and Python than C#. Surely that makes them better at generating what they’ve seen the most?
I don’t think it does, because raw corpus size isn’t what an agent needs. An agent needs two things from a language: clear guidance on structure and patterns of the codebase, and a cheap way to verify its own work.
On the first count, .NET is a unified, coherent ecosystem maintained by a single entity. I would go as far as to say it’s a rather small ecosystem, as there are rarely competing libraries fulfilling the same purpose. With one answer to every question, the LLM knows where to look and how to generate code. The Node world has a lot of data to train on, but with three runtimes, five ORMs and a new state-of-the-art HTTP client every quarter, the model samples across all of them and happily mixes idioms mid-codebase.
Verification is the second half.
The type system of C# is nothing to write home about, but it gets you 95% of the way.
It’s pretty comparable to TypeScript’s, better than Python’s tack-on of typechecking,
weaker than Rust’s but compiles fast (this matters a lot to an agent iterating in a loop),
compiles a bit slower than Go but it’s much more expressive.
C# 15 will finally see the introduction of the union keyword for discriminated unions, too.
And the types run end to end: EF Core types the database access, the OpenAPI spec types the frontend contract.
A change is typed from the database row to the React component, so an agent’s mistakes rarely survive the first build.
AI coding favours batteries-included, cohesive frameworks. LLMs work really well with Django for the same coherence reasons. But Django is showing its age: type hints are awkward to retrofit, async is painful, options for OpenAPI generation are poor. What makes .NET stand out is that it’s stable, modern and performant at once.
Whatever the exact mechanism, the result in my experience is that LLMs just “get” .NET codebases. They pick the idiomatic approach, compile first or second try, and rarely hallucinate a dependency.
The microservices retreat
Agents also have opinions about architecture. The engineering community is currently undergoing a correction for the microservices craze of the 2010s. Modular monoliths are back in vogue. This trend gets a second wind with AI coding, as an agent can trace a change end to end through one codebase, whilst a change spanning services fragments into contexts it can’t hold at once.
A modulith makes one big demand of its language - it has to be good enough at everything. Node concedes the hot paths, Python concedes… a lot, and Rust leaves you filling ecosystem gaps yourself. The whole modulith bet rests on a language that stretches across CRUD, background jobs, CPU-heavy work without leaving the process, LLM agents, and even ML inference in some cases.
C# ticks all these boxes, and the platform around it was practically designed for this architecture:
- compile-time enforced boundaries through projects and assemblies
- solution structure that mirrors architecture
- first-class dependency injection and composition
- multiple DB contexts to keep each module’s data private
and the list goes on.
The first-party ecosystem is solid even for things like agentic workflows (see Microsoft Agent Framework) and ML (see ML.NET).
The flip side of that small, coherent ecosystem, and of the culture Microsoft cultivated around it, is a thin third-party scene compared to TypeScript, Python or Java. But missing dependencies are increasingly cheap to fill with LLMs. Missing some niche library from Python? Ask your favourite agent to port it and it will probably just do it. The same dynamic aids Rust’s adoption too, but Rust’s gaps are of a different kind. A missing library to camelise strings is an hour of agent work, while a missing ORM is a major undertaking whose design the language itself resists.
The perception inversion
The general perception is that .NET is for large organisations, whereas the trifecta are for innovative startups. This may be true of who’s actually using them today, but the technical reality is backwards.
An early-stage team has no room for specialisation. The same two engineers ship the CRUD, the background jobs, the billing integration and the one CPU-heavy feature that makes the product interesting. This is where the two-language tax hurts the most. What a startup needs is one batteries-included platform that’s good enough across the board.
Once you’re big enough to truly justify multiple languages, the equation flips. Boring CRUD or third-party integrations? TypeScript. Performance-critical services or microservices in complex domains where the stronger type system pays dividends? Rust. ML services? Python.
.NET’s advantage is largest at exactly the company size that won’t touch it, and smallest at the scale where everyone assumes it belongs.
That startups have not discovered .NET is mind-blowing and a testament to the stigma around it. But this stigma has been slowly eroding, and I see more voices advocating for .NET in the community. Certainly enough that LLMs are quick to give it credit where it’s due. This shouldn’t matter much, but sadly in a world where leadership decisions are increasingly made by asking the oracle, it does.
Risks
C# is unusual among mainstream languages in how tightly it’s coupled to a single big tech firm. Whether this is a good thing or a bad thing on balance is up for debate. It’s certainly led to mistakes and the current negative perception. Undeniably, it’s a major risk to my bet - if anything kills .NET, it will be Microsoft shifting its investment to TypeScript, the biggest competitor it happens to own.
But the same coupling is a unique advantage where trust matters.
In regulated environments dealing with a lot of sensitive data,
a .csproj with five dependencies (and all of them from Microsoft) is a serious selling point.
The alternative on offer is the npm ecosystem and its steady stream of supply chain attacks.
The other obvious objection is the JVM. Much of .NET is comparable to the JVM ecosystem, Spring in particular. The JVM won’t be going anywhere for the foreseeable future, so this is not an either-or question. But I’d give the edge to .NET due to the coherence argument from earlier. The JVM is a fragmented world: three languages, two build systems, competing frameworks for everything, and a modernisation stuck halfway, with Kotlin’s backend uptake stubbornly slow.
Some people say Go has a bright future with agentic coding. That might be true, but I believe Rust will eat Go’s lunch. Go’s strength has always been simplicity for humans, which is exactly the advantage AI makes irrelevant. In any case, it’s not a direct threat to the large modulith use case .NET occupies, as Go’s type system is simply too limiting for complex business backends - no sum types, minimal generics, and little help modelling a rich domain.
Which leaves the one risk I can’t argue away, the perception simply not shifting fast enough. .NET wouldn’t be the first great technology to lose to politics and marketing.
Conclusion
The original post’s trifecta covers a lot of ground, and all three languages are hard to unseat from the domains they occupy. But none of them feels like a robust default for the boring backend, the largest domain left unclaimed.
So which language will come fourth, and join the trifecta in the age of agentic engineering? The breadth of its applications and the coherence of its ecosystem make C# the dark horse of the race.
My bet is that C# slowly but steadily sheds its stigma and increasingly becomes a default for greenfield projects with complex backends. If Microsoft doesn’t kill it first, that is.