
TSX Costs 94% More LLM Tokens Than Pug
TSX Costs 94% More LLM Tokens Than Pug
We usually think about markup as something a browser reads.
That is no longer the only reader.
Give a React component to Claude, Cursor, or another coding agent and ask it to add a field, change a breakpoint, or move an element. The model has to read the component before it can change it.
That means the markup itself has become part of the token bill.
A recent experiment by Andrey Kucherenko measured four ways of writing the same web structures: HTML, Pug, JSX, and TSX.
The result is surprisingly consistent.
Across five samples, Pug used the fewest tokens. TSX used the most. Overall, TSX required about 94% more tokens than Pug to represent the same structures.
But the interesting part is not simply that Pug is shorter.
It is where the extra TSX tokens actually come from.
The original study is Part 3 of Andrey Kucherenko's "The Tokenomics of Web Development" series.
What was actually measured?
The comparison used four formats:
- HTML
- Pug
- JSX
- TSX
There were five examples for each format:
- A heading and paragraph
- A three-item list
- A login form
- A card
- A semantic article with a header, two sections, and a footer
The examples were deliberately kept static.
No application logic. No event handlers. No data fetching.
The structure, classes, text, and nesting were kept equivalent. The main difference was the syntax used to express them.
Token counting used OpenAI's tiktoken with the cl100k_base encoding.
That detail matters.
Tokenizers are not universal. Different models can split the same source differently. The study itself notes that newer Claude models use a newer tokenizer that produces roughly 30% more tokens for the same text. Specialized tokenizers attack exactly this problem — see Gigatoken's 989x-faster Rust tokenizer.
So the exact numbers should not be treated as universal.
The ranking is the more interesting part — and rankings deserve scrutiny. See a fair-comparison methodology for Rust tokenizers before trusting any single benchmark table.
The ranking did not change
Across all five examples:
Pug was first. HTML was second. JSX was third. TSX was last.
The same order appeared every time.
The overall multipliers reported by the study were approximately (results table):
Pug ×1.000
HTML ×1.608
JSX ×1.879
TSX ×1.944
So TSX was about 1.94 times the token count of Pug in this particular benchmark.
That is where the "94% more" headline comes from.
It is worth being precise here.
This does not mean TSX always costs 94% more tokens than Pug. It means that, in these controlled examples, the total TSX representation was about 94% larger than the Pug representation under the tokenizer used.
That's a much more useful way to read the result.
The obvious suspect is not actually the problem
If you have spent any time discussing React verbosity, you have probably heard the usual explanation:
JSX is expensive because of
className.
The benchmark tested that assumption.
It doesn't hold up.
Under cl100k_base, class and className each tokenized as a single token. Across the examples, the study found the same total token count for the class and className attributes.
So changing:
class="card"
to:
className="card"
is not the reason JSX becomes expensive.
There is a more interesting culprit.
The component wrapper
The JSX examples contained the component machinery around the markup.
Something like:
export const Card = () => (
...
);
That wrapper is not part of the HTML structure.
It is code around the structure.
When the researcher stripped that wrapper away and counted the markup body separately, something interesting happened: for several samples, the JSX body had exactly the same token count as the equivalent HTML.
For the list, form, and card examples, the markup itself added no token overhead compared with HTML.
The difference came from the surrounding JavaScript.
The study calculated about 11 tokens per component wrapper across the examples.
TSX then added another small cost:
: React.FC
That type annotation was three tokens per component in the benchmark.
Five components produced (TSX-over-JSX breakdown):
3 × 5 = 15 tokens
So the TSX-over-JSX difference was much smaller than the headline suggests.
That is an important distinction.
The expensive part is not necessarily "React markup".
It is often the code surrounding the markup.
HTML loses to Pug for a simpler reason
HTML has a different problem.
Closing tags.
Consider:
<p class="meta">text</p>
versus:
p.meta text
The visible result is effectively the same.
The Pug version removes the closing tag and compresses the attribute syntax.
In the article sample used in the study, 15 closing tags accounted for 48 tokens — around 31% of that sample's token budget (study table).
Pug does not need them because indentation carries the structure.
The same applies to attributes.
Instead of:
<p class="meta">text</p>
Pug can write:
p.meta text
The text itself takes the same number of tokens in the example. The difference comes from the structural syntax around it.
That's the part the tokenizer has to read even though the browser ultimately gets the same structure after compilation.
There are actually two different kinds of overhead
The benchmark shows an interesting difference between HTML and the JavaScript-based formats.
HTML's overhead tends to grow with the markup tree.
More elements mean more opening and closing syntax.
JSX and TSX have another component: a fixed cost around the tree.
For a very small component, that wrapper can make up a surprisingly large percentage of the prompt.
As the component gets larger, the fixed cost becomes less important.
That explains why the smallest example in the study had a much larger TSX-to-Pug ratio than the larger article example.
The wrapper stays roughly the same size.
The markup grows around it.
Pug wins on both characters and tokens
Another interesting result is that Pug was not simply winning because it had fewer characters.
It also had the best token-per-character result among the four formats in this benchmark.
HTML had the worst compression.
JSX and TSX were longer in raw characters, but their JavaScript-heavy syntax was relatively familiar to the tokenizer.
That makes an important distinction:
Source length and token count are related, but they are not the same thing.
A shorter file does not automatically produce fewer tokens, and a longer file does not necessarily produce proportionally more.
The tokenizer matters.
Does this mean we should all switch to Pug?
No.
Not even close.
The benchmark measures token consumption. It does not measure how accurately an AI coding agent understands each format, how often it makes mistakes, or how much debugging is required afterward.
And that matters.
Pug has far less representation in modern frontend code than JSX.
A model may simply be more familiar with React and JSX.
If an agent needs two attempts to produce the correct Pug component but gets the JSX version right on the first try, the theoretical token saving may disappear immediately.
The study explicitly does not claim to measure that trade-off.
So this is not an argument for rewriting React applications in Pug.
It is an argument for understanding where token overhead comes from.
The useful lesson for React developers
There are a few practical takeaways here.
1. Don't blame className
If you are trying to reduce token usage, replacing className with some clever abstraction is unlikely to make a meaningful difference.
The benchmark found that class and className cost the same number of tokens in the tested samples.
2. Component boundaries have a cost
Every time a piece of markup becomes another component, you introduce some surrounding code.
That cost is small for one component.
Across hundreds of components, it adds up.
This doesn't mean "use giant components."
It means component extraction should have a reason beyond making a file look shorter.
3. The file you send matters
If an AI agent only needs to modify the markup inside a component, sending imports, wrappers, unrelated helpers, and configuration along with it creates unnecessary context.
Sometimes the cheapest prompt is simply the smallest useful slice of the source.
4. Repeated context is where this becomes interesting
One extra wrapper is not going to bankrupt anyone.
The bigger question is repetition.
If the same source file is sent through an agent repeatedly during implementation and review, the same structural overhead gets paid repeatedly. Reasoning-heavy agents pay it most — one reason distilling reasoning efficiently matters.
That is where token efficiency starts becoming an engineering concern rather than a benchmark curiosity.
The context-window angle matters more than the dollar figure
Token prices change.
Model pricing changes. Tokenizers change. Context windows get larger.
That makes a statement like "TSX costs X dollars more than Pug" much less useful than the underlying ratio.
The more durable finding is that the same UI can require substantially different amounts of model input depending on how it is represented.
A TSX component using roughly 1.94× the tokens of its Pug equivalent occupies roughly 1.94× the input-token budget for that representation.
That matters when an agent is repeatedly reading source code, especially in workflows where multiple files are kept in context.
It doesn't automatically mean worse output.
It means there is less of the context budget available for everything else.
And that distinction is important.
This changes how we should think about "code size"
Developers already measure code in several ways.
Lines of code.
Characters.
Bundle size.
Compressed JavaScript.
Build time.
Runtime memory.
Now there is another dimension:
How expensive is this source code for a model to read?
A 200-line component might be perfectly reasonable for a browser and perfectly reasonable for a human.
But if an AI agent has to read it dozens of times during development, its representation has another cost.
That does not make token count the most important metric.
It just means it is a metric we previously ignored because humans do not pay per token to read source code.
Models do.
A simple experiment you can run yourself
You don't need a complicated benchmark to check your own code.
Install tiktoken and count a file:
import sys
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
with open(sys.argv[1], "r", encoding="utf-8") as f:
source = f.read()
print(len(enc.encode(source)), "tokens")
Then try the same thing after removing the component wrapper.
For a React component, compare:
complete component
↓
markup body only
↓
token count difference
That gives you a rough idea of how much of the file is actual UI structure and how much is component ceremony.
Just remember that the result depends on the tokenizer.
The number you get from cl100k_base is not necessarily the number used by the model you are currently running.
What this benchmark actually tells us
The interesting conclusion isn't:
Pug is better than TSX.
It isn't.
The more useful conclusion is:
The way we write the same interface can change how much text an AI system has to process.
In this benchmark, Pug was the cheapest representation.
HTML cost more because of its structural syntax.
JSX added a component wrapper.
TSX added a small type annotation on top of that.
And className — the thing developers often point at — turned out not to be the problem.
That is a much more useful result than simply ranking four markup languages.
For years, we have optimized source code for humans and browsers.
Now AI coding tools are another consumer of that source.
Maybe the next generation of frontend tooling will measure not only bundle size, but model-facing source cost as well.
We already have linters for code quality and analyzers for browser performance.
A token budget for the code that agents have to read doesn't sound quite so strange anymore.
Sources
- We Measured the LLM Token Cost of 4 Markup Formats — Andrey Kucherenko / HackerNoon
- tiktoken — OpenAI
- Claude Platform Pricing and tokenizer notes — Anthropic
Sources
- HackerNoon: We Measured the LLM Token Cost of 4 Markup Formats: TSX Costs 94% More Than Pug
- OpenAI: tiktoken
- Anthropic: Claude Platform Pricing and tokenizer notes
// author
Editor & Operator
Mohd Firdaus Abu Bakar (MrDodgerX) is an enterprise geospatial systems engineer in Malaysia and the editor behind hejes.my. He runs the briefing pipeline, curates and edits every draft, verifies each factual claim against primary sources, and presses the publish button — nothing ships without his review. He writes about AI, security and Malaysia's tech scene from a builder's perspective. Professional profile and code: the links below.
// sources //
fact-check verified · 09 SEPT 2026 · hejes-content-fact-check
- We Measured the LLM Token Cost of 4 Markup Formats: TSX Costs 94% More Than PugHackerNoon · accessed 09 SEPT 2026
- tiktokenOpenAI · accessed 09 SEPT 2026
- Claude Platform Pricing and tokenizer notesAnthropic · accessed 09 SEPT 2026
related //

Splintr vs Gigatoken: A Fair Comparison of Rust Tokenizers
A reader said splintr beats gigatoken. After studying its benchmarks, the answer is nuanced: it wins on flexibility and latency, gigatoken on raw throughput.

Gigatoken: 989x Faster Tokenization in Rust
Gigatoken is an MIT-licensed Rust tokenizer that encodes an 11.9 GB corpus at 24 GB/s — up to 989x faster than HuggingFace and 681x faster than tiktoken.

Apriel-H1: Distill Reasoning, Not Pretraining Data
ServiceNow turns a 15B reasoning model into a Mamba hybrid at 2.1x throughput. The interesting part is how they chose the distillation data.
// join the feed
one fresh insight per week. no spam, ever.
weekly digest. unsubscribe anytime.