How to Upload Multiple Files to ChatGPT at Once
- Drop the folder on fileconcat.com and you get one text file: the tree first, then every file in a block labelled with its path.
- Pasting files one at a time loses the boundaries. The labels cost 0.6% to 3.8% of the bundle and are the map the model reads by.
- The token count is on the result before you paste. A whole public repository is a median 236,218 tokens, and 23 of 60 fit a 128K window.
- Nothing is uploaded to us, the whole thing runs in your browser.
You have a handful of files that belong together: a few source files, some notes, a config or two. ChatGPT and Claude give you a single box. Getting everything from the folder into that box, in a shape the model can follow, is the small chore that sits between you and the actual question.
This is a practical guide to uploading multiple files to ChatGPT at once, or to Claude, by combining them into one: what the quick approaches cost you, what a labeled bundle looks like, and a place partway down to try it on your own files.
01 of 6
Why one paste of everything falls short
A chat box takes one block of text. When you paste file after file into it, the bytes
arrive, but the boundaries do not. The model sees one long run of characters with no
reliable signal for where math.ts ends and date.ts begins.
Pasting them one at a time is how most people try to combine multiple text files into one for an AI prompt, and it is exactly where the structure leaks out. Handing over a stack of loose pages is not the same as handing over a labeled folder. Same content, very different odds the reader keeps track of it.
What 'one prompt' actually is
Most chat boxes accept a single block of text. The task is to turn many files into one block that still tells the model where each file starts, ends, and sits in the tree.
02 of 6
Three ways to combine your files
There are three common ways to merge text files into one for an LLM, and they trade effort against structure.
- 1
Copy and paste by hand
Fine for two or three files. Past that it gets tedious, and every paste drops the file path, the one label that tells the model what it is looking at.
- 2
Concatenate on the command line
cat src/*.tswill concatenate multiple files into one file in a second. What it will not do is add file headers, skip lock files and build output, or tell you how large the result is. You get the bytes and none of the structure. - 3
Bundle it with FileConcat
Drop the folder in your browser. The noise gets filtered out, every file is wrapped with its path, and you copy one structured document with the token cost shown up front.
The gap between the second and third option is what the rest of this guide is about.
Here are the same two files, first as a raw cat dump, then as a labeled bundle:
export function add(a, b) {
return a + b
}
export function formatDate(d) {
return d.toISOString()
}<file path="src/math.ts">
export function add(a, b) {
return a + b
}
</file>
<file path="src/date.ts">
export function formatDate(d) {
return d.toISOString()
}
</file>03 of 6
Try it with your own files
The fastest way to see the difference is on your own files. Drop a folder or a few files below. It runs entirely in your browser, there is no account, and nothing is uploaded to us. What you get back is one clean prompt you can drop into ChatGPT or Claude.
Try it with your own files
Drop a folder or a few files. It runs here in your browser, nothing is uploaded.
04 of 6
Why the labels matter
The labels are not decoration. A file path is the cheapest context you can give a
model: it says that src/math.ts is a module, that date.ts sits beside it, and that
a file named index.ts is probably an entry point. Strip the paths and the model has
to infer all of that from the code alone.
The tree at the top of the bundle does the same job at a larger scale. It lets the model see the shape of the project before it reads a single line, the way you would glance at a file explorer before opening anything. That is what lets you combine multiple files into one prompt for an AI without turning it into a guessing game.
They are also cheaper than they look. Measured across five codebases containing 248 files, the entire wrapper, paths and fences and tree together, came to between 0.6% and 3.8% of the bundle, and the choice between XML, Markdown and plain labels moved the total by only 0.24% to 1.13%. The labels are close to free; see XML vs Markdown for LLM context for the measurement.
Paths are the cheapest context you can add
If you keep only one thing from a raw cat dump, keep the file paths. A few extra
tokens of path="..." buy the model a map it would otherwise have to guess at.
05 of 6
Upload multiple files to ChatGPT as one
ChatGPT counts files, not bytes. OpenAI's File Uploads FAQ allows 80 files every 3 hours, and 3 a day on the Free plan, as of September 2026, and a Project holds a set number of files per plan. A bundle is one file however many went into it, so twenty source files and a spec cost one upload and take one Project slot. Every cap by plan: the ChatGPT file upload limit, and for Projects, the ChatGPT Projects page.
06 of 6
How many tokens is that?
The other thing the chat box has is a ceiling: it accepts only so much text at once. So it helps to know the size of a bundle before you paste it, not after it bounces back.
A loose folder of notes and a few source files is rarely the problem. A whole repository usually is. We tokenized 60 public repositories end to end, and the median one assembled into 236,218 tokens:
| Context window | Repositories that fit |
|---|---|
| 128,000 | 23 of 60 |
| 200,000 | 26 of 60 |
| 1,000,000 | 43 of 60 |
So the median repository clears a 1M window and misses a 128K one. The method and the per-language spread are in how many tokens is a codebase.
FileConcat counts tokens live as you build the bundle, so you see that number before you paste rather than after.
The default filter leaves out the parts you almost never want to send: lock files, build output, vendored code, and test files by their ecosystem's naming convention. It is worth knowing what that buys. On a fresh clone the defaults remove a median 22.7% of tokens, most of it the test suite, and a median 73.7% of files survive them. If you need a much smaller bundle, the lever is deciding that a whole category does not belong in this question, not a stricter filter.
Tip
Working with a whole repository instead of a loose folder? You can paste a GitHub, GitLab, or Bitbucket URL and bundle it the same way, filtering and token count included. See importing from GitHub.