Repomix vs gitingest vs code2prompt: 60 Repositories Measured
Measured on September 10, 2026 and kept as measured. FileConcat has changed since; what it reads today is listed in the formats list.
We ran all four over the same 60 public repositories at their own defaults and looked at what each bundle holds. FileConcat is ours, so every number comes with its method below, including the ones that count against us.
01 of 10
Which one should you use?
Pick on what you need in the bundle first, and on what it costs second.
| If you want | Pick | Why |
|---|---|---|
| the most of your own code for the tokens | FileConcat | the densest bundle on most repositories, and the cheapest on about half |
| PDF, Word, Excel or PowerPoint files next to the code | FileConcat | the only one of the four that reads them |
| tests and CI files in, without changing a setting | Repomix | keeps every test and hidden file, for about a fifth more tokens |
| a Python toolchain | gitingest | close to the cheapest on most repositories; check what it skipped on large ones |
| one binary, nothing to install | code2prompt | check its Markdown: a file's own code block can end that file early |
The first row is what the figure below measures. A bundle that is mostly your own code spends its tokens on the part you are asking about. The rest of a bundle is tests, lockfiles, vendored libraries and generated files, which cost tokens and rarely answer the question.
The densest bundle was ours on 35 of the 60 repositories, gitingest's on 16, code2prompt's on 5, Repomix's on 4.
median share across the 60 repositories, each tool at its own defaults, 2026-09-10
Size is a smaller difference than it looks. Three of the four land within about a tenth of each other on a typical repository, and code2prompt comes out close to twice as big. The wrapper each tool writes around the files, the part people argue about most, is under a fifth of one percent of a bundle. What decides the size is which files a tool leaves out.
None of this says which bundle a model answers better from. It measures what reaches the model, which is the part you can check before you paste.
02 of 10
The one thing only one tool did
A document sitting next to the code is where the four stop being the same kind of tool.
We gave each one a folder holding a source file and four documents, each carrying a sentence that appears nowhere else:
| Tool | main.ts | report.pdf | notes.docx | figures.xlsx | deck.pptx |
|---|---|---|---|---|---|
| FileConcat | text | text | text | text | text |
| Repomix | text | absent | absent | absent | absent |
| gitingest | text | absent | listed, no text | listed, no text | listed, no text |
| code2prompt | text | absent | absent | absent | absent |
Only FileConcat's bundle had all four sentences. gitingest wrote an entry for three of the files with nothing under it, and Repomix and code2prompt left them out. The real sample said the same: 7 of the 60 repositories hold such a document, and ours was the only bundle that carried its text.
That is a difference in what these tools are for, not a defect in them. The other three describe themselves as packing a codebase, and a PDF is not code. If your context is source plus a spec, a contract or a paper, reading the document is the whole job, and what gets lost converting documents to text measures how well we do it.
03 of 10
What our defaults leave out
FileConcat leaves out more by default than the other three, and two of those things you might want.
Tests. The defaults drop test files by their name, so on a typical repository our bundle keeps about a sixth of the test code where the other three keep all of it. If your question is about the test suite, that is the wrong default: clear the test patterns from the Ignore field in the settings drawer, or tick the files back in the tree.
Hidden files. In the browser only a file whose own name starts with a dot is held back, so
CI workflows under .github/workflows come through and .editorconfig does not. A held-back
file stays in the tree, one tick from the bundle. Repomix and gitingest keep every hidden file
without a setting.
Measuring this also caught one of our defaults being wrong: a vendored-code folder named
3rdparty was not on the list. It is now, and every number here is from the run after the
fix. What the filter leaves out lists every default, and is worth
reading before you trust any tool's, ours included.
Drop a project folder below and watch the token count as you include and exclude files. It runs in your browser, there is no account, and nothing is uploaded to us.
Count your own repository
Drop a project folder. It runs here in your browser, nothing is uploaded.
Whichever tool you land on, run it on your own repository before you trust a typical number. The spread across the 60 was wide, and the file that decides your bundle is one only your repository has. For the how-to rather than the comparison, feeding a codebase to an LLM covers the filtering and the paste.
04 of 10
What the four tools are
| Tool | How you run it | Written in | Default output | What you point it at |
|---|---|---|---|---|
| Repomix 1.18.0 | npm CLI | TypeScript | XML | a local directory, or a remote repository |
| gitingest 0.3.1 | Python CLI, and a hosted site | Python | plain text digest | a local directory or a GitHub URL |
| code2prompt 4.2.0 | a release binary | Rust | Markdown | a local directory |
| FileConcat 0.4.0 | a web page, and an npm CLI | TypeScript | XML | files and folders in the browser, a repository URL, or a local directory |
A fifth, repo2txt, is a web page that reads a repository through the GitHub API. It has no local mode, so it could not be pointed at the same checkout as the others and it is not in the numbers below.
05 of 10
How we measured it
One shallow clone per repository, pinned to a fixed commit, with all four tools run over that same directory. No tool was allowed to clone for itself, because two clones are two trees. The only flags passed were the ones that choose where the bytes go.
The 60 repositories are the same sample as how many tokens a codebase is, drawn by a GitHub search query written before the results were seen.
The run was made three times. The first, on 2026-09-08, is what this post was first
published with. Our own defaults then changed, tests by file-name convention on 2026-09-09
and bun.lock on 2026-09-10, so the sample was re-run at the same pinned commits on
2026-09-10, this time recording for every file in every checkout which bundles carry it.
That run showed 3rdparty missing from our list on one repository, the list changed, and
the sample ran a third time the same day. Every number here is the third run's.
Repomix and code2prompt reproduce every one of the 60 bundles to the token across the three runs. gitingest does not: at the same commit its bundle differed on 4 of the 60 checkouts between the second run and the third and on 6 between the first and the third, by at most 5,613 tokens and never more than 0.2% of the bundle, and running it three times by hand on one of those checkouts returned a different file missing each time. Every larger move is ours, and the section on our own defaults says which way.
A tool is credited with a file only when the file's own first and last 200 characters are in
its bundle. A per-file marker alone is not enough: gitingest writes a FILE: line for 459
paths across the sample and then leaves them empty, binaries, fonts, archives and office
files, and a count of markers would have credited it with text it never wrote.
06 of 10
What the same repository costs
| Tool | Median bundle | vs that repo's cheapest | at p90 | Cheapest on |
|---|---|---|---|---|
| FileConcat | 235,672 | 1.00x | 1.19x | 31 of 60 |
| Repomix | 239,861 | 1.21x | 1.90x | 4 of 60 |
| gitingest | 258,790 | 1.04x | 2.11x | 20 of 60 |
| code2prompt | 432,539 | 1.40x | 3.83x | 5 of 60 |
Three of the four sit between 235,672 and 258,790 tokens at the median and code2prompt sits at 432,539. FileConcat produced the cheapest bundle on 31 of the 60 and gitingest on 20, and at the median both are within 4% of the best available bundle for that repository. Repomix is at 1.21x there; tests are 47.3% of what it carries and we do not, and vendored code 42.7%.
The interesting part is the tail. At p90 our bundle is 1.19x the best available one for that repository, Repomix 1.90x, gitingest 2.11x, code2prompt 3.83x, and code2prompt's worst case is 16.4x: 24,116 tokens against 396,180 on the same checkout of GeminiProChat.
When this was first published, on the 2026-09-08 run, gitingest was cheapest on 27 of the 60 and we were on 10. Nothing about gitingest's defaults changed. Ours did, and what that removed is sized below rather than left as a win.
07 of 10
The wrapper is a rounding error
Every one of these tools writes a preamble saying what the file is and how a model should read it. It is the most visible difference between them and the easiest thing to argue about. One directory, one twelve-byte file, everything above the content is wrapper:
| Tool | Wrapper tokens |
|---|---|
| gitingest | 24 |
| code2prompt | 30 |
| FileConcat | 104 |
| Repomix | 364 |
The largest of those is 364 tokens, against a median cheapest bundle of 218,688. That is 0.17%. Pick your tool on its preamble and you are tuning under a fifth of one percent of the thing you are about to paste. The floor grows with file count, because every tool also draws a file tree, but not by an order of magnitude.
08 of 10
The disagreement is about what gets left out
If it is not the wrapper, it is the filter. Across the 60 repositories another tool bundled 9,022 paths that we did not, and our own walk records why for each one:
| Why our bundle does not have it | Files | Characters |
|---|---|---|
| our default ignore list | 7,715 | 81,457,778 |
| hidden file or directory | 1,054 | 1,464,678 |
| never reached our walk | 215 | not measurable |
| not treated as text | 38 | 36,292 |
| your .gitignore | 0 | 0 |
The default list is 85.5% of the paths and 98.2% of the characters. Hidden files are 11.7% of the count and 1.8% of the size: CI workflows, editor config, repository metadata, all small. When this was first published the default list was 31% of the count and hidden files were 56%; the test convention that landed on 2026-09-09 is what moved it.
Per competitor, Repomix carried 8,296 files and 68,326,261 characters that we did not, gitingest 8,105 files and 50,733,196 characters, code2prompt 7,708 files and 80,503,695 characters: the fewest files of the three and the most characters, which is what including lockfiles looks like. The reverse is nearly empty at the level of paths: in 55 of the 60 repositories every path in our bundle was at least listed by one of the other three, and across the whole sample 5 paths were ours alone. What we carry that they do not is not a path but the text inside a document, which has its own section above.
Ranking the 60 repositories by the single largest file we left out and another tool kept,
the answer is package-lock.json in 7 of them, Cargo.lock in 4, go.sum in 2, a
pnpm-lock.yaml and a bun.lock once each, and on 3 repositories a test file. On
GeminiProChat that one lockfile is 562,067 characters, which is the whole 16.4x.
Fewer tokens is not the same as better
A tool that produced a smaller bundle because it dropped the file you needed has not saved you anything. That cuts against us too, and the section on our own defaults puts numbers on it.
09 of 10
What each bundle is made of
Every file in every bundle was classified with the category rules of
the codebase study: source, tests, documentation,
configuration, assets, lockfiles, generated, vendored, with documents pulled out of their
category and hidden files counted again across all of them. The rules are ours, path-based
and ordered, and a competitor might draw a line differently; print them with
pnpm --filter @fileconcat/cli measure-funnel --rules. Signal density is the source share
of a bundle's tokens, and it is the one number that says what a token bought.
| Share of the bundle, median | FileConcat | Repomix | gitingest | code2prompt |
|---|---|---|---|---|
| source | 68.0% | 49.6% | 51.1% | 38.8% |
| tests | 0.7% | 9.4% | 9.0% | 9.0% |
| documentation | 7.9% | 6.0% | 5.5% | 2.8% |
| configuration | 0.9% | 2.0% | 1.8% | 0.4% |
| hidden, any category | 0.0% | 0.8% | 0.7% | 0.0% |
Each row is its own median, so a column does not add to 100. Lockfiles, generated files and vendored code are 0% of the median bundle for three of the four and 1.6% for code2prompt; the tail is where they live. At p90 that noise is 0% of our bundle, 7.7% of Repomix's, 17.8% of gitingest's and 66.4% of code2prompt's. Of what code2prompt carries that we do not, 36.3% is vendored code, 19.4% lockfiles and 6.2% generated files; for gitingest, lockfiles are 16.6% of it and vendored code 14.4%.
Density is half the picture, because a tool can be dense by dropping source. So the second
cut is coverage: of the checkout's visible source tokens, how much each bundle carries. The
third is whether the boundaries in the bundle can be trusted. A file whose own content
carries the tool's delimiter at the start of a line, </file>, a line of 48 equals signs or
three backticks, is a boundary a model cannot tell from the real one.
| Tool | Visible source carried, median | at p10 | Files carrying the tool's own delimiter |
|---|---|---|---|
| FileConcat | 100.0% | 99.7% | 0 |
| Repomix | 100.0% | 99.4% | 0 |
| gitingest | 100.0% | 93.5% | 0 |
| code2prompt | 99.8% | 97.2% | 380, in 58 of 60 repositories |
Three tools carry all of the visible source at the median and code2prompt nearly does. The p10 column is where they part. gitingest's worst repository is pomerium, where it dropped 444 source files and carried 59.1%. It also drops every SVG, 0.0% of its sample total against between 4.8% and 7.0% for the other three, which is defensible and unstated, and it names 459 paths it does not carry, so a count of its markers overstates its bundle.
On boundaries, code2prompt's Markdown fence collides with a file's own code block in 58 of the 60 repositories, 380 files with 738,003 tokens inside them, and a reader, human or model, cannot tell where those files end. FileConcat, Repomix and gitingest had zero collisions across 37,275 files.
10 of 10
Where our own defaults cost you
Our defaults are the most aggressive of the four and that is not free. Two things the other tools carry and we do not, each sized so you can decide.
The first is tests. Since 2026-09-09 the default list drops test files by the naming
convention of each ecosystem, api.test.ts, handler_test.go, test_parser.py,
parser_spec.rb, UserServiceTest.java and their siblings, and the directory a test sits in
no longer decides anything. Before that it dropped directories named __tests__ and kept
index.test.ts beside them, one suite with two answers, which is the inconsistency the
change replaced. Re-running the sample at the same pinned commits, it took tests from 17.5%
to 5.5% of kept tokens and the whole sample down 13.1%.
Of a checkout's test tokens, our bundle now carries a median 15.6%, 5.8% at p25 and 79.5% at p75, where the other three carry 100%. Tests are 47.3% of what Repomix holds that we do not, 66.1% for gitingest and 37.9% for code2prompt. Vendored code is another 42.7%, 14.4% and 36.3% of the same, nearly all of it one directory on one repository, named below. Count everything a reader might have wanted, every category except lockfiles, generated files and vendored code, hidden or not, and we carry a median 94.0% of it, 70.4% at p25 and 56.1% at p10, against 100% for Repomix, 97.9% for gitingest and 96.3% for code2prompt. If you are reviewing the suite, we are the wrong default. On the web, delete the test patterns from the Ignore field in the drawer or tick the files in the tree; the CLI applies the default list unconditionally and has no flag that turns part of it off.
The second is hidden files, and here the measurement is of the CLI. Anything under a dot
directory is invisible to the CLI by default, and to code2prompt, and visible to Repomix and
gitingest. Hidden source exists in 19 of the 60 checkouts; it is 0.1% of a checkout's source
at p90 and 7.3% at the most. CI workflows are configuration under our rules rather than
source, and in the 49 repositories that have them they are 0.4% of the checkout's text at
the median and 2.8% at the most. Small, but if you are asking a model about your CI it is
the whole question. The CLI includes them only through a config file with
excludeHiddenFiles: false; there is no flag, and --no-hidden sets what is already the
default. The browser draws the line differently: only a file whose own name starts with a
dot is held back, so .github/workflows/ci.yml comes through and .editorconfig does not,
and a held-back file shows in the tree where a tick puts it back.
A third was ours alone, and this measurement closed it. 3rdparty was not in the default
list, so on KDE's ghostwriter the second run put 9,374,207 tokens in our bundle against
gitingest's 2,843,609, 90.4% of ours vendored code under that one directory. 3rdparty,
third_party and thirdparty joined vendor in the defaults on 2026-09-10 and the sample
ran a third time at the same commits: that checkout is now 861,968 tokens for us, the
cheapest of the four, and no other bundle of ours moved.