Blog

How Many Tokens Is a Codebase? 60 Repositories Measured

CeamKrier
Key findings6 findings
236,218
Median tokens for a whole public repository turned into one LLM-ready artifact, across 60 repositories in 10 languages. The spread is what matters: 34,860 at the 10th percentile, 3,044,662 at the 90th.
38%
Share of the 60 repositories that fit a 128,000 token context window. 43% fit 200,000 and 72% fit 1,000,000. A window big enough for the median repository is not big enough for the ones people actually struggle with.
22.7%
Median share of tokens the defaults remove from a fresh clone, and more than half of that is the test suite, dropped by file name since 2026-09-09. Before that rule the same defaults removed 3.5%: a clone has no node_modules and no build output, so what a filter removes from one is code somebody named.
12.4% vs 1.6%
Hidden files are 12.4% of the files the defaults exclude but 1.6% of the tokens. The default ignore list is 87.0% of the files and 97.8% of the tokens. Any sentence about what a filter removes is wrong until it names its unit.
70.7%
Share of kept tokens that are source code, pooled across the sample. Documentation is 8.6%, text-encoded assets such as SVG 7.1%, configuration 6.5%, and the tests the naming rule does not see 6.4%. Per repository the source share median is 71.8%, with a quarter of repositories below 48.7%.
2.5%
Median token cost of the bundle wrapper itself, the XML tags and header and file tree. We were not counting it. On one repository of many small files it was 18.6%.
2026-09-11 / 60 public repositories, 39,107 files, 55,092,425 tokens

Every tool that turns a folder into LLM context tells you it removes the noise. None of them tells you how much noise there was, what the rest is made of, or what is left after. The number people quote for their own repository is usually the one their editor's status bar showed them once.

So we measured it. Sixty public repositories, ten languages, three size bands, every file routed through the same engine the tool ships, every bundle assembled and tokenized whole, and the same 60 commits measured again each time a default changed, so every number here is the shipped build's. Three results change what you should do with your own folder.

Your repository probably does not fit where you think

Half of the 60 land between 60,831 and 1,201,507 tokens. Only 38% fit a 128,000 token window, and 28% do not fit 1,000,000.

Count yours before you pick a model

A filter removes what somebody named, not what is big

The defaults removed a median 22.7% of tokens from a fresh clone, and 11.9% of every token in the sample was a test file dropped by its name. Before that rule the same defaults removed 3.5%.

Decide what belongs in this question, not what looks like noise

Read the unit on any reduction claim

The same exclusion is 12.4% of the files removed and 1.6% of the tokens removed. Both sentences are true and they mean different things.

Ask any tool which one it counted, ours included
dataset
60 public GitHub repositories
sample
39,107 files walked
tokenizer
o200k_base via tiktoken
measured
2026-09-11

01 of 12

How many tokens is a codebase, exactly?

There is no single answer, and the distribution is the finding. Half the repositories in our sample sit between 60,831 and 1,201,507 tokens. That is a factor of 20 inside the middle half alone.

60 public repositories, smallest to largest60 rows / log scale
128K window23 of 60200K window26 of 601M window43 of 602M window50 of 60
1k100k10M

Each row is one repository. A window fits every row ending left of its line.

The largest is certd/certd, an SSL certificate renewal tool whose monorepo carries a web front end, a server and one deployment plugin per hosting provider, at 5,535,907 tokens. The smallest bundles come from single-purpose libraries with a handful of source files. In the first two runs the largest was KDE/ghostwriter at 9,373,193, and 8,633,558 of that was a vendored 3rdparty directory our defaults did not know the name of; it is 861,866 tokens now, and the fix is in the list of our own defects below.

20x

Between the 25th and 75th percentile. Not the whole range, the middle half. There is no typical codebase size to plan around, which is why a rule of thumb fails here and a measurement does not.

60,831 to 1,201,507 tokens / 60 public repositories / 2026-09-11

02 of 12

What nobody had measured yet

We checked what is already published before measuring. Two kinds of claim exist and neither answers the question.

The first is tool marketing. Repomix, the most widely used tool in this category, documents its Tree-sitter compression as "~70% token reduction" in its own README. That is a claim about an optional compression mode, measured against the tool's own uncompressed output, not a claim about how much of a repository is worth sending. Gitingest and the rest publish no figure at all.

The second is the long-context literature, which measures what happens to a model as input grows but never says how big a repository is in the first place. Liu et al. found that performance "is often highest when relevant information occurs at the beginning or end of the input context, and significantly degrades when models must access relevant information in the middle of long contexts". Chroma's 2025 evaluation across 18 models found that "across all experiments, model performance consistently degrades with increasing input length". Both are about the cost of a large context. Neither tells you whether your repository produces one.

Nobody has published the funnel: files in, text out, filters applied, tokens produced, over a sample large enough to show a distribution. That is what this is.

03 of 12

The 60 repositories, and how they were picked

The sample was pre-registered. One GitHub search query per cell, written before any result was seen, and the first two results taken in the order they came back. No repository was added, dropped, or swapped after seeing what it measured.

language:<L> size:<band> stars:100..5000 pushed:>2026-03-07
archived:false is:public mirror:false template:false
sort=stars order=desc

Ten languages: TypeScript, JavaScript, Python, Go, Rust, Java, C#, PHP, Ruby, C++. Three size bands from GitHub's own size field, in KB: small 0.1 to 2 MB, medium 2 to 20 MB, large 20 to 200 MB. Two repositories per cell, 60 in total. Every one of them cloned at depth 1 on 2026-09-07, with the commit recorded, and every rerun since has measured those same 60 commits.

The star ceiling is the filter doing the most work. A floor of 100 keeps abandoned experiments out. A ceiling of 5,000 keeps the sample from becoming a list of exceptional mega-projects and curated link collections, which are not what anyone drops into a context window. The full list, the query, the replacement rule for a failed clone, and the biases are in packages/cli/scripts/repo-sample-2026-09-07.txt.

Two repositories in the draw turned out to be documentation collections rather than codebases. They were kept, because removing them after seeing them would turn a query into a choice. They are named in the results, at the top of the documentation share, exactly where they were predicted to land.

04 of 12

How we counted the tokens

Every decision in the measurement comes from the shipped engine. There is no second implementation of the classifier, the filter, or the tokenizer, because a reimplementation measures a tool nobody uses.

  1. 1

    Clone at depth 1 and record the commit

    A shallow clone, so the measurement describes repository content and not version control history.

  2. 2

    Walk every file, including hidden ones

    .git is excluded because it is the version control database rather than repository content. Counting it would drown every other number.

  3. 3

    Decide what is text the way the product decides

    Content signature routing first, then the encoding classifier. Documents such as PDF and DOCX go through the same parser registry the CLI uses, so a PDF that yields text counts as text.

  4. 4

    Apply the defaults, and record which one fired

    Hidden files, the default ignore list, and any .gitignore in the tree. Each excluded file is attributed to the first rule that removed it.

  5. 5

    Assemble the bundle and tokenize it whole

    The artifact is built with the product's own assembler, in the default XML style, and tokenized in full. This is what a reader pastes into a model, wrapper and file tree included.

The category map (source, tests, documentation, configuration, assets, lockfiles, generated, vendored) is ours and is a judgment call, not a standard. Nothing in a repository declares that a path is a test. The rules are ordered and first match wins, because a vendored test is vendored and a lockfile is a lockfile before it is JSON configuration. Print the full map with pnpm --filter @fileconcat/cli measure-funnel --rules. Assets are images in a text encoding such as SVG: the defaults keep them, and until the map was revised on 2026-09-10 for the tool comparison they were counted as source. Every composition figure below is cut under the current map.

05 of 12

What 60 repositories actually weigh

The funnel

All 60 repositories, pooled
files in the clone39,107
minus 1,814, binary, or no readable text (4.6%)
text the engine can read37,293
minus 8,884, hidden, default ignore list, or gitignore (23.8%)
kept by the defaults28,409
unit changes, files to tokens
55,092,425
tokens of context
from 28,409 files
1,939 tokens per file, average
Claude Sonnet 523.6% of the window0.34 USD per send

The model tail describes the median repository rather than the pooled total: 236,218 tokens is 23.6% of Claude Sonnet 5's 1,000,000 token window, and costs about $0.34 to send once at the catalogue's cheapest listed provider on 2026-09-11.

Two things in that funnel are smaller than people expect.

A fresh clone is almost entirely text. 37,293 of 39,107 files, 95.4% pooled and a median of 97.1% per repository. Binary assets are rarer in a repository than in a working folder, and the engine reads more formats than "text file" usually means.

22.7%

All the defaults take off a fresh clone, and more than half of it is the test suite. The rest of what a filter is famous for removing was never committed, so if you were counting on filtering to get a repository under a context window, this is the number that says it will not.

median across 60 fresh clones / 3.5% before tests were dropped by name

The defaults remove a fifth, and unevenly. A median of 73.7% of files survive. The token distribution is heavily skewed: the 25th percentile loses 2.2% and the 90th loses 70.0%. Thirty-nine of 60 repositories lost more than 10%. Two lost nothing at all.

This is a floor, not the reduction you will see

A fresh clone has no node_modules, no dist, no build output and no local env files, because none of that is committed. The generated and vendored shares measured here are the smallest they can be. On a working folder the same filters remove far more. We cannot measure that from clones, and we are not going to estimate it.

The same exclusion, counted two ways

Here is the result that changed how we describe our own product.

The same exclusion, counted two ways
hidden filesfired in 58 of 60
12.4%
share of excluded files
1.6%
share of excluded tokens
default ignore listfired in 52 of 60
87.0%
share of excluded files
97.8%
share of excluded tokens
a .gitignore in treefired in 6 of 60
0.6%
share of excluded files
0.5%
share of excluded tokens

Count files and one exclusion in eight is a dotfile. Count tokens and it is one in sixty.

A tool that says "removed 40% of files" and a tool that says "removed 40% of tokens" have not told you the same thing, and neither has told you which one they meant.

The .gitignore row is the one we did not expect. Honoring .gitignore is a feature we built and describe; on a fresh clone it fires in 6 repositories out of 60, because the things a .gitignore names are the things that were never committed.

What the bundle is made of

Composition by token, all 60 repositories, per-file counts9 categories
48%
kept, 53,603,450 tokens25,273,232 excluded
source38,137,34248%
docs4,626,9616%
assets3,840,5965%
config3,528,2724%
tests3,470,2794%
excluded by default
tests, by name9,525,69712%
vendored9,164,59812%
lockfiles4,892,6736%
build output1,690,2642%

Of the tokens that reach the bundle, 70.7% are source, 8.6% documentation, 7.1% assets in a text encoding, 6.5% configuration and 6.4% tests. The hatched segments never arrive, and the largest of them is the test suite the defaults drop by file name.

Pooled shares hide the variation, and the variation is the useful part:

Category25th percentileMedian75th percentileHighest
source48.7%71.8%88.4%96.6%
tests0.0%0.7%6.6%85.1%
docs2.8%8.2%21.2%99.5%
config0.1%0.9%3.1%97.5%
assets0.0%0.0%1.8%86.7%

The tests row is what survives the naming rule, and its tail is the rule's limit: one repository in ten is still more than a third tests, and jarro2783/cxxopts is 85.1% tests, because its suite lives under names the convention does not cover. If you are pasting a repository to ask about behaviour rather than to review the suite, that remainder is yours to remove, because a test is legitimate source code and only the named part of it can be dropped by a default.

The two documentation repositories the sample drew are the top of the docs column exactly as predicted: gopl-zh/gopl-zh.github.com at 99.5% and SwiftOldDriver/iOS-Weekly at 99.2%.

By language

Six repositories per language is a spread check, not a league table. Read the shape, not the ranking.

LanguageMedian kept, filesMedian bundle tokensMedian source shareMedian tests share
TypeScript70.3%82,76270.5%1.4%
JavaScript80.8%139,08848.7%0.2%
Python71.1%144,92082.7%0.0%
Go64.2%244,36551.5%0.1%
Rust82.2%579,33174.0%0.8%
Java78.4%478,60564.1%4.3%
C#84.0%380,20481.6%0.3%
PHP69.0%106,92275.8%4.5%
Ruby72.3%246,29451.5%12.1%
C++68.3%790,55391.7%0.2%

Go keeps the fewest files, because a _test.go sits beside most source files and the defaults drop it by name. The C++ repositories are nearly ten times the size of the TypeScript ones and almost entirely source. Ruby's median repository still carries the highest test share after the naming rule, which is the rule's limit showing: what it does not name, it does not remove.

Against a context window

The four dashed lines on the figure above are these: 23 of 60 fit 128,000 tokens (38.3%), 26 fit 200,000 (43.3%), 43 fit 1,000,000 (71.7%) and 50 fit 2,000,000 (83.3%).

More than half of these repositories do not fit in a 200,000 token window. A million-token window takes 72% of them, which is the number that makes the long-context literature above relevant rather than academic: the repositories that need the big window are exactly the ones sitting deep inside it, where measured accuracy is worst.

06 of 12

Four things we found wrong in our own tool

The measurement was built to describe repositories. It described our product instead: three times on the day, and once more when the same sample was walked beside three other tools. All four are fixed, and every number on this page comes from the fixed build, rerun on the same 60 commits.

1. The default ignore list was missing go.sum

In the run before the fix, 95 lockfiles reached bundles carrying 886,586 tokens, and every one of them was a go.sum. testcontainers-go alone shipped 789,477 tokens of dependency checksums, roughly three times the median repository's entire bundle, in a file whose contents no model can use.

Fourteen other lockfile names were already on the list. This one was an omission, not a decision. go.sum is now excluded and go.mod is explicitly kept, because the manifest is the part a reader wants. Pipfile.lock and gradle.lockfile went in alongside as siblings of the same oversight, though neither appeared in this sample and we claim nothing about them.

2. The token counter was not counting the artifact

The readout tokenized the file contents joined together. The XML root, the per-file tags, the header and the file tree are all sent to the model and all charged for, and none of them were in the number.

Measured over the sample, the wrapper is a median 2.5% of the bundle, 5.1% at the 75th percentile, and 18.6% on sintaxi/harp, where 147 small files mean the tags outweigh what they wrap. The counter now counts the same string the preview shows and the copy button copies.

3. Above 1 MiB the count was a guess with the wrong ratio

Tokenizing a multi-megabyte bundle in a browser is slow enough to freeze a tab, so above 1 MiB of text the tool stopped tokenizing and forecast the count as characters divided by four. That ratio is English prose. It was applied to Chinese, to minified assets, to anything.

Twenty-seven of the 60 repositories cross that threshold. Scored against the real count of the same bundles, the old figure was a median 11.6% off, 48.2% off at the 90th percentile, and 62.5% low on SCIR-HI/Huatuo-Llama-Med-Chinese, where a character is closer to one token than to four. Five of those 27 repositories were within 5% of the truth.

The fix keeps the reason the threshold exists and drops the assumption: 64 evenly spaced 4 KiB slices are tokenized for real, and the count is scaled by the ratio those slices show. The cost is a flat 256 KiB of tokenizing, whatever the bundle's size. How that budget is spent was tuned against the truth rather than picked, on the four repositories the first configuration did worst on:

SlicesMean absolute errorWorst case
16 x 16 KiB8.14%17.0%
32 x 8 KiB2.82%8.7%
64 x 4 KiB1.30%1.9%
128 x 2 KiB0.79%1.3%

The error is coverage, not sample volume: the same 256 KiB spread over more positions reads a heterogeneous bundle far better. 64 x 4 KiB is the shipped setting rather than the marginally better 128 x 2 KiB, because every slice cuts two tokens in half at its edges, a bias that grows with the slice count, and the gain past that point sits inside the noise of a four-repository comparison.

Across the same 27 estimated repositories, the shipped setting is a median 0.8% off, 2.1% at the 90th percentile, and 3.2% at worst. All 27 are now within 5% of the truth, against 5 of 27 before. Counting the whole sample, including the 33 repositories small enough to be tokenized exactly, 49 of 60 readouts are now within 1% of what a paste actually costs. Before both fixes, one was.

4. Two more names were missing: bun.lock and 3rdparty

On 2026-09-10 the same 60 commits were walked beside Repomix, gitingest and code2prompt for the tool comparison, which reads what each tool carries path by path, and two of our omissions were only visible from the outside. bun.lock reached our bundle in four repositories, 490,966 tokens of resolved dependency graph between them, and on KDE/ghostwriter a directory named 3rdparty put 8,633,558 tokens of vendored code into a bundle of 9,374,075. vendor had been on the list from the start; the other name the same thing travels by was not. Both went in on 2026-09-10, third_party and thirdparty beside them as spellings, and the rerun on 2026-09-11 moved those five repositories and no other: ghostwriter to 861,866 tokens, the four bun.lock repositories by between 20,499 and 400,854 each, and the remaining 55 reproduce to the token.

07 of 12

What this means when you bundle your own

Ask what your repository is before asking which model fits it. The median here is 236,218 tokens and the 90th percentile is 3,044,662. Those two repositories have nothing in common as context problems. The first fits anywhere; the second does not fit anything, and no filter setting will change that.

A filter removes what is named, and the rest is a decision. On a clone the defaults remove a median 22.7% of tokens, and 11.9% of every token in the sample was a test file dropped by its name; before that rule the same defaults removed 3.5%, because the node_modules a filter is famous for was never committed. What moves the number past that is deciding that a whole category does not belong in this particular question: the documentation at 8.6% of kept tokens, the tests the rule does not see at 6.4%. That is a choice about intent, and a default cannot make it for you.

Read the unit on every claim, including ours. 12.4% against 1.6% is the same exclusion described twice. Whenever a tool tells you how much it removed, the first question is what it counted.

Fitting is not being read

Every repository here that needs a million-token window lands exactly where the published accuracy studies measured the worst retrieval. Getting the bundle to fit is the easy half.

Liu et al. 2023 / Chroma 2025 / see the references

A bigger window is not a free pass. The repositories in this sample that need a million-token window are the ones that land where Liu et al. and Chroma both measured the worst accuracy. Fitting is not the same as being read.

08 of 12

Limitations

  • A fresh clone is not a working folder. No node_modules, no build output, no local env files. The generated and vendored shares are a floor and the real reduction on a developer's machine is larger. We did not measure it, and we are not going to guess it.
  • The sample spreads over language and size, not popularity. Sorting by stars descending under a 5,000 star ceiling means every repository sits near that ceiling. A well-known project carries more CI configuration, more tests and more lockfiles than a private work repository, so the non-source share here likely overstates what a solo developer's folder looks like.
  • Six repositories per language. Enough to show that ecosystems differ, not enough to rank them.
  • The category map is ours. Nothing in a repository declares a path to be a test or generated. The rules are published and ordered, and a different reasonable map would move the composition figures.
  • The tokenizer is OpenAI's. o200k_base via the o1-preview-2024-09-12 encoding. Claude and Gemini tokenize differently, so every token figure here is an approximation for those targets. That is true of the product's own readout as well.
  • The composition split is per-file, the bundle figure is the whole artifact. They differ by the wrapper and by the joins between files, which is why the composition bar's total is slightly below the bundle total of 55,092,425. Do not mix the two.
  • The measured wrapper is a floor. The shipped tool adds one more header line naming the image and binary files it left out, capped at ten paths. The measurement never fills that list, so a repository carrying binaries pays a slightly larger wrapper than the 2.5% median here.
  • This measures what reaches the model, not what helps it. Whether a filtered bundle produces better answers than a raw one is a separate experiment that needs a model in the loop. It is not this one.

09 of 12

Reproduce it

Everything needed is in the repository. The sample list is tracked next to the script that consumes it, so the selection is auditable rather than described.

git clone https://github.com/CeamKrier/file-concat
cd file-concat && pnpm install
pnpm --filter @fileconcat/cli measure-funnel --repos scripts/repo-sample-2026-09-07.txt
pnpm --filter @fileconcat/cli analyze-funnel

Add --pin <a previous run's JSON> to the first command to measure the commits that run measured instead of each repository's current HEAD, which is how the reruns below were made.

The first command writes a JSON record with a row per repository: the three stages, the token figures, the per-category split with kept and excluded separated, which rule excluded each file, and the skip counts. The second prints every cut quoted on this page but two, and both are marked where they appear: the go.sum figures describe the run before that fix, which the fixed build cannot produce again, and the slice tuning table comes from a separate comparison over four repositories. The commit measured for each repository is recorded in the output, and a rerun pinned to it reproduces the file counts and the token totals. The first run, on 2026-09-07, could not be reproduced that way, because the file tree was rendered in directory-walk order until the day it was published and two clones of one commit could order siblings differently; the tree has been sorted since.

The defaults changed twice after the first run, and the sample was re-run at the same 60 commits each time to say by how much. On 2026-09-09 the default ignore list stopped ignoring directories named __tests__ and started ignoring test files by each ecosystem's own naming convention: api.test.ts and api.spec.js, handler_test.go, test_parser.py, parser_spec.rb, UserServiceTest.java, OrderTests.cs, PaymentTest.php, ParserTests.swift. On 2026-09-10 bun.lock and the 3rdparty family joined the list. The page above is the third run; this is what each change moved:

figure2026-09-07, first published2026-09-09, tests by name2026-09-11, this page
median bundle246,424 tokens236,218 tokens236,218 tokens
tokens across the whole sample73,763,19064,095,711, 13.1% fewer55,092,425, 25.3% fewer
median share of files kept87.5%74.2%73.7%
median share of tokens the defaults remove3.5%21.4%22.7%
hidden files, as a share of what the defaults removed63.1% of files, 5.7% of tokens13.8% and 2.5%12.4% and 1.6%
the ignore list, same two shares33.9% of files, 92.5% of tokens85.6% and 96.7%87.0% and 97.8%
tests, as a share of kept tokens17.5%5.5%6.4%
source, as a share of kept tokens70.6%80.8%70.7%
largest bundle9,373,193, KDE/ghostwriter9,374,075, KDE/ghostwriter5,535,907, certd/certd

The first change moved 42 of the 60 down and 18 up, the latter by 3,158 tokens in total, which is the folder-grouped tests coming back now that __tests__ is not ignored for its name. The drops landed where the language table predicts: the five largest were Ruby and PHP repositories, the two languages with the highest test shares in the first run, led by simplecov-ruby/simplecov at 52.8% and catfan/Medoo at 52.1%. The second change moved five repositories and no other, KDE/ghostwriter by its 3rdparty directory and four by a bun.lock.

The last column also recuts every file under the eight-category map, which is why source falls from 80.8% to 70.7% of kept tokens while nothing was removed from it: 7.1% of kept tokens are text-encoded assets that the seven-category map had counted as source, and ghostwriter's departure changed the pool every other share is taken over.

The limit of the test rule is that it is naming, not detection. A tests/ directory whose files carry no convention survives, Rust's integration tests in tests/*.rs survive, and a suite that does not follow its ecosystem's spelling survives. Tests at 6.4% of kept tokens is what remains after the named part is gone, not proof that 6.4% is all the test code there is.

dataset60 public GitHub repositories drawn by a pre-registered GitHub search query, 10 languages x 3 size bands x 2 repositories
sample39,107 files walked, 37,293 text eligible, 28,409 kept by the defaults, 55,092,425 tokens assembled
measured2026-09-11, on the 60 commits first cloned on 2026-09-07
build@fileconcat/core 2.0.0, the commit that added 3rdparty and bun.lock to the default ignore list
tokenizero200k_base via @dqbd/tiktoken, the o1-preview-2024-09-12 encoding, run over the assembled XML bundle
scriptpackages/cli/scripts/measure-repo-funnel.ts, with analyze-repo-funnel.ts for the cuts
excludesWorking folders, private repositories, model accuracy, and any language outside the ten sampled. A fresh clone carries no build output, so generated and vendored shares are a floor.

10 of 12

Count your own folder

The numbers above are a distribution. Yours is one point in it, and the only one that decides anything. Drop a folder here and the same engine runs on your machine: nothing is uploaded to us, the whole thing runs in your browser. If the destination is a ChatGPT Project, whose limit is a file count, the bundle takes one of its slots; the per-plan caps are on the ChatGPT Projects page.

Run the funnel on your own folder

Files in, text out, what the defaults keep, and what it costs to send. Nothing is uploaded.

11 of 12

Frequently asked questions

How many tokens is my codebase?

If it is a typical public repository, somewhere between 34,860 and 3,044,662, with a median of 236,218. That range is the honest answer, which is why the tool counts your actual folder instead of guessing. Language matters more than you would think: the median C++ repository in our sample was 790,553 tokens and the median TypeScript one 82,762.

Does removing node_modules and lockfiles shrink a repository a lot?

On a fresh clone the defaults remove a median 22.7% of tokens, and more than half of that is test files dropped by name; before that rule existed the same defaults removed 3.5%. node_modules is not committed, so it is not there to remove. On a working folder the same filters remove much more, because that is where the installed dependencies and build output live. What does shrink a clone is a lockfile or a vendored directory, which is why one missing entry in our ignore list cost 886,586 tokens across four Go repositories and another cost 8,633,558 on one repository.

Will my repository fit in a 1M token context window?

Seven in ten of our sample did: 43 of 60. But fitting is not the same as being used well. Both studies in the references below found accuracy falling as input grows, so a repository that just barely fits a window is sitting in the worst part of it.

Should I strip tests before pasting a codebase into an LLM?

It depends on the question you are asking, and it is the biggest lever available. Tests were 17.5% of all kept tokens in the first run over this sample and more than 41.5% in the top quarter of repositories. Since 2026-09-09 our default ignore list removes test files by each ecosystem's naming convention, which takes that share to 6.4% on the same 60 repositories: 11.9% of every token in the sample is a test file dropped that way. That is naming rather than detection: a tests/ directory whose files carry no convention still comes through, as do Rust's tests/*.rs, so strip the rest yourself when the question is about behaviour rather than about the suite.

Why does the token count differ between tools?

Because tools count different things. Some count file contents only and leave out the wrapper they add, which we measured on ourselves at a median 2.5%. Some estimate from character counts rather than tokenizing, which we also did above 1 MiB and which ran a median 11.6% off. And any tool using an OpenAI tokenizer is approximating when you paste into Claude or Gemini.

12 of 12

References

Liu et al., "Lost in the Middle: How Language Models Use Long Contexts"
TACL vol. 12, 2024
Multi-document QA and key-value retrieval, relevant information moved through the context

Where an answer sits inside a long input, across model sizes

Performance "is often highest when relevant information occurs at the beginning or end of the input context, and significantly degrades" in the middle, "even for explicitly long-context models"

Chroma Research, "Context Rot: How Increasing Input Tokens Impacts LLM Performance"
Industry report, 2025
18 models, 8 input lengths x 11 needle positions

Retrieval and replication tasks as input length grows

"Across all experiments, model performance consistently degrades with increasing input length"

Repomix (yamadashy/repomix)
Project README
Not a study

Its own Tree-sitter compression mode against its own uncompressed output

"~70% token reduction", a claim about optional compression rather than about repository composition

Tip

The measurement script and the repository list are both in the public repository. If you disagree with the category map, change it and rerun: the numbers on this page are an output, not an assertion.