Your Programming Language Costs Tokens: What AI Writes Best

When AI writes part of your code, your programming language stops being just a matter of taste or hiring. It has a direct cost: every syntactic puzzle the model has to solve is paid in tokens — the unit models compute in and bill by — and every hard-to-read line is paid in human review time. Steve Yegge, co-author with Gene Kim of the book "Vibe Coding" (IT Revolution, late 2025), reports generating on the order of a million lines of code in a year using swarms of coding agents. His takeaway: TypeScript turns out to be expensive under heavy agent use, because models burn a disproportionate share of tokens untangling complex type acrobatics or fabricating syntactic escape hatches. Go, by contrast, he describes as an excellent infrastructure language for vibe coding: readable, predictable, no-frills syntax that the human doing the checking can actually review. The lesson is not "rewrite everything in Go." It's more useful than that: for a new service, "easy for a human to review, predictable for a model" has become a legitimate stack criterion — right alongside ecosystem and hiring.

A million lines later: what Yegge saw

Steve Yegge didn't try three prompts on a Sunday afternoon. He co-wrote "Vibe Coding" with Gene Kim (IT Revolution, late 2025), and he works with agent swarms: multiple coding agents running in parallel on the same projects. At that scale — he talks about roughly a million generated lines in a year — friction stops being anecdotal. It becomes a pattern.

And the pattern he reports is counterintuitive: TypeScript, the default choice for so many web teams, is the language that makes agents sweat the most. Not because it's bad. Because its type system, powerful as it is, creates situations where the model goes in circles.

Why TypeScript burns tokens

An agent writing TypeScript has to satisfy the compiler. With simple types, no problem. But once a project accumulates nested generics, conditional types, or type-level metaprogramming, the model enters an expensive loop: it proposes code, the compiler complains, it fixes, the compiler complains again. Every lap around that loop costs tokens.

Here's the kind of code that triggers the loop:

type ApiResponse<T> = T extends { data: infer D }
  ? { ok: true; payload: D }
  : { ok: false; error: string };

Elegant for the human who designed it. A trap for a model that has to produce code compatible with it across twenty files.

And when the model can't win, Yegge describes the second behavior: it fabricates escape hatches.

// @ts-ignore
const user = response as any as User;

That's a double loss: you paid the tokens for the losing battle, and you're left with a silent workaround that cancels exactly what your types were supposed to guarantee.

One important nuance: the problem isn't TypeScript itself, it's type sophistication. TypeScript with flat, explicit types remains perfectly workable for an agent.

What Go gets right

Yegge describes Go as an excellent infrastructure language for vibe coding, and his reasons fit in three words: readable, predictable, no-frills.

func (s *Store) GetUser(ctx context.Context, id string) (*User, error) {
	var u User
	err := s.db.QueryRowContext(ctx,
		"SELECT id, email FROM users WHERE id = $1", id,
	).Scan(&u.ID, &u.Email)
	if err != nil {
		return nil, fmt.Errorf("get user %s: %w", id, err)
	}
	return &u, nil
}

This code is boring. That's exactly the point. In Go there's usually one idiomatic way to write something, gofmt enforces a single canonical format, and errors are handled explicitly, line by line. The result:

  • the model has fewer choices to make, so fewer chances to improvise;
  • you can review fast — and that's the key, because when AI writes the code, your job shifts from writing to reviewing.

A "boring" language is no longer a flaw. It's a feature you actively want: your ability to verify what the AI produced depends directly on how easy its code is to read.

The four AI criteria for a stack

Beyond the TypeScript-versus-Go matchup, you can score any language or framework on four axes once part of the code will be generated:

  • Human reviewability. You'll read far more than you write. Code that reviews quickly makes verification cheaper.
  • Predictability for the model. The fewer ways there are to write the same thing, the less the model improvises. Strong conventions channel generation: the AI follows the rails.
  • Verbosity, i.e. cost per feature. Every generated token gets billed. For the same feature, a framework that demands three config files costs more than one that needs none. Don't confuse verbosity with readability, though: Go is a bit verbose but highly readable, and that's a good trade.
  • Ecosystem stability. An ecosystem that breaks its API every six months pushes the model to blend the versions it saw during training. Fewer diverging versions means less code calling functions that no longer exist.

A convention-heavy framework — the classic "convention over configuration" — often checks three of these boxes at once.

You don't rewrite anything

Let's be clear: none of this justifies rewriting an existing app. Your production code has value that saved tokens can't match: it's tested, debugged, and understood by your team. Rewriting to "optimize tokens" means destroying that capital for a marginal gain.

The criterion becomes legitimate at the moment of an actual choice: a new service, a new project, a separate piece of infrastructure. At that point you're already weighing ecosystem, hiring, and library maturity. "Cost and reliability of AI generation" simply joins the list, at the same rank as the others. Not above them: if your team lives in npm and your product depends on React, a restrained, well-conventioned TypeScript backend is still a rational choice.

Where to start

You don't need to switch stacks tomorrow. Here are concrete moves, ordered by effort:

  1. If you're staying on TypeScript: keep types simple and explicit, ban type-level metaprogramming from application code, and block as any and @ts-ignore in CI (ESLint handles this).
  2. Pin your versions and write them into your agent's context file (CLAUDE.md or equivalent): "Next 15, Prisma 6, Node 22". The model improvises less when it knows what it's working with.
  3. Pick convention-heavy frameworks for any new project: fewer open decisions means less improvisation from the model.
  4. For your next service, run a real test: generate the same feature in two candidate stacks. Compare the number of round-trips with the agent, how easy the review felt, and how much you trust the result.
  5. Add one line to your stack-selection checklist: "AI cost" (reviewability, predictability, verbosity, stability), right next to "hiring" and "ecosystem".

That's the real takeaway: your language has become an interface between you and the model. Choose it the way you'd choose an API — readable, predictable, stable.