Train on the repository, not the file.
Almost every code model before this one was fed source code as a pile of loose files, shuffled and cut into fixed-length windows. That throws away the one thing real engineering runs on: a file rarely stands alone — it imports other files, and the definitions it uses live somewhere else in the project.
DeepSeek-Coder's bet is that this organization matters as much as raw scale. Two moves carry the whole paper: build the corpus at the repository level, ordering files so that whatever a file imports comes before it; and train not only left-to-right but with a fill-in-the-middle objective, so the model learns to complete code with context on both sides.
A file rarely stands alone. So the corpus shouldn't either.
From orbit
What ships, and where the real bet is hiding.
Step 1 · The black box
A code model — and the corpus is where the bet lives.
From the outside DeepSeek-Coder is the model you'd expect: a decoder-only Transformer that takes some code as context and predicts what comes next. It ships in four sizes — 1.3B, 6.7B, 33B, plus a 5.7B mixture — each with a base version (raw pretraining) and an instruct version (fine-tuned to follow requests).
cart.py from a tiny shopping-cart project. This little repo follows us from the corpus all the way to the benchmarks.Trained from scratch on 2 trillion tokens across 87 languages, the 33B base model tops open peers and clears closed models like Codex and GPT-3.5 on standard code tests. But sizes and scores are the visible part. The interesting question is why a from-scratch open model closed that gap — and the answer is on the input side, not the architecture side.
Architecture, in one breath: decoder-only Transformer, RoPE positions, SwiGLU, trained with AdamW. The 33B adds grouped-query attention for inference speed — machinery it shares with most 2024 LLMs, so we won't dwell on it here.
Step 2 · The silent bug
Chop a repo into loose files and the definitions vanish.
The model reads context and predicts code. So everything rides on what context it saw during training. Here's the habit DeepSeek-Coder set out to break.
Look at our specimen. cart.py computes a total — but the two
names it leans on, catalog.Product and money.usd,
are defined in other files. That's normal Python: you import what you
need. The trouble starts when a corpus is built one file at a time.
cart.py can land in a training window with catalog.py and money.py nowhere in sight — the model reads a use with no definition.
This is the silent bug. Standard code corpora shuffle files and pack them
into windows, so a model routinely sees catalog.Product used
without ever seeing class Product. It can memorize surface
patterns, but it never gets to learn the dependency — the thing
real projects are made of.
So the fix writes itself: before packing anything, arrange each project's files so that whatever a file imports appears earlier in the sequence. Definitions first, uses second. The rest of Part B is how you do that automatically, for millions of repositories.
Step 3 · The corpus pipeline
Five stages turn raw GitHub into ordered training samples.
We know the goal now — put a file's imports before it. Zoom out one level: that reordering is a single stage inside a five-stage assembly line that turns raw repositories into training data.
The team crawled public repositories created before February 2023, kept 87 languages, and pushed everything through the line below. The star of this page is the third box — dependency parsing — which we open up for the rest of Part B.
Crawl
Public repos, 87 languages, created before Feb 2023.
Filter
StarCoder-style rules drop low-quality files — down to ~32.8% of raw size.
Parse deps
Read imports, sort each project so dependencies come first.
Dedup
Near-duplicate removal — at the repo level, not the file level.
Screen
Compiler + quality model, then n-gram scrub against the test sets.
Final tally: 798 GB, 603 million files, 87 languages. Roughly 87% source code, 10% code-related English (GitHub Markdown, StackExchange), 3% Chinese text. The pipeline picture is redrawn from Figure 2 of the paper.
The corpus machine
Two ideas, both hands-on: order the files, then cut a hole.
Step 4 · Reading the imports
Every import is an arrow; count the arrows into each file.
Stage 3 promised to put imports first. To do that automatically, the parser first turns the whole project into a picture: a dependency graph.
The rule is deliberately simple — scan each file for invocation lines
(import in Python, using in C#,
#include in C) with regular expressions. Each import becomes a
directed arrow drawn from the file being imported to the file that
imports it. Read an arrow as “this end must come first.”
A file's in-degree is just how many files it imports. In-degree 0
means “needs nothing” — safe to place anytime.
cart.py has in-degree 2: it can't go down until both
catalog.py and money.py are already placed.
Step 5 · Sort it by hand
Place a file only after everything it imports is down.
You have the graph and you have in-degrees. That's everything you need to do the sort yourself — no algorithm required yet, just the one rule: a file is ready the moment all of its imports are already placed.
Build the training sample below. Ready files glow; blocked ones stay dim
until you clear what they need. The order you produce is exactly what gets
concatenated into one training document — with a # path
comment stitched onto each file so the model always knows where it is.
Click files in a legal order — imports before importers
The single training document you're assembling
Two files are ready: config.py and money.py.
What to notice: flip the checkbox and catalog.py's
in-degree jumps to 2 — it stops being ready until money.py is
down too. Change the imports, and the legal orders change with them. There
is usually more than one valid answer.
Step 6 · The receipt, and two catches
Pick the least-blocked file — cycles and islands included.
The moves you just made by hand have a name: a topological sort. Here is the paper's Algorithm 1, and it is nothing more than a receipt for the rule you already used — take a ready file, place it, then relax whatever it was blocking.
The subtle word is smallest, not zero. A textbook topological sort demands an in-degree of exactly 0 and gives up if none exists. Real import graphs aren't so polite — two files can import each other, forming a cycle where nobody ever reaches 0.
This is the spot that took me a couple of reads to see clearly. By always taking the least-blocked file instead, the algorithm never stalls: on a clean project it behaves exactly like the ordinary sort you did in Step 5, and on a tangled one it still produces a reasonable order instead of throwing up its hands.
Catch 1 · cycles
Each imports the other. “Smallest in-degree” still moves — “zero” would freeze.
Catch 2 · islands
Unconnected clusters are found first, then each is sorted separately.
The label
A # path comment rides along, so location survives into training.
Simplification we're glossing: the parser only tracks import-style calls via regex — it isn't a full type resolver, so some real dependencies slip through. And near-duplicate removal (Stage 4) runs on the whole concatenated repo as one unit, precisely so this ordering isn't torn apart by deduping individual files.
Step 7 · Fill in the middle
Cut a hole, move the tail up front, learn to fill the gap.
Ordering fixes what the model reads. The second idea fixes which direction it reads. Plain next-token training only ever predicts forward — but in an editor you usually have code on both sides of your cursor.
So during pretraining, half the documents get rewritten. Take a line from
our cart.py, slice it into three pieces — a
prefix, a middle, and
a suffix — then reorder them so the middle
comes last. Now “predict what's next” means “fill
the hole, having read both sides.” That's Fill-in-the-Middle (FIM).
Slide the two cuts — the hole moves, the training sequence rebuilds
The line, with the hole you carve out
The reordered training sequence — PSM mode
What to notice: whatever you cut, the coloured
middle always lands at the end, right
after the ⟨fim_end⟩ marker — that's the only place the model
has to produce. The prefix and suffix are just context it reads first. PSM
and SPM only change the order of that context.
The paper tests 0%, 50%, and 100% FIM. A 100% rate wins the infilling
benchmark but hurts ordinary left-to-right completion — a real
trade-off — so DeepSeek-Coder settles on a 50% PSM rate, applied per
document before packing. The real markers are
<|fim▁begin|>, <|fim▁hole|>,
<|fim▁end|>.
Does it hold up
The scores, and the one number that pays back Part B.
Step 8 · The scoreboard
A 33B open model clears Codex and GPT-3.5.
Recipe in hand, the payoff is blunt: on the standard code tests the biggest base model beats every open peer and the closed models the paper set out to catch.
The bars compare DeepSeek-Coder-Base 33B against CodeLlama-Base 34B — a near-identical parameter budget — on three code suites, plus one instruct-model result against GPT-3.5-Turbo.
Higher is better · pass@1, greedy decoding
vs CodeLlama-34B
vs CodeLlama-34B
vs CodeLlama-34B
vs GPT-3.5-Turbo
Numbers from Tables 3–6. The 33B is DeepSeek-Coder-Base unless marked Instruct; CodeLlama figures were re-run by the authors under one shared harness for a fair comparison.
Step 9 · The payoff for Part B
Turn repo-ordering off and cross-file accuracy drops.
Those scoreboard suites are mostly single-function puzzles — they can't actually see whether repository ordering helped. So the paper runs the one test that can: complete a line that depends on another file.
This is the clean ablation. Same model, same retrieval setup, measured on CrossCodeEval — then the whole thing retrained on a plain file-level corpus with the Part B ordering switched off. The bars are exact-match accuracy; cinnabar keeps the repo-level ordering, grey drops it.
This is the whole thesis, measured. The only thing that changed between the two bars is whether the corpus was ordered by the dependency graph you sorted by hand in Step 5. Order the files, and the model gets better at the one task single-file training can't teach.
Step 10 · Say it back
The recipe, in your own words.
You built the corpus and read the payoff. Try the five questions below before opening each answer — if the sort and the hole both feel obvious now, the paper has landed.
Why order files inside a repository at all?
Because a file's definitions live in the files it imports. Order imports first and the model reads a definition before its use, so it can actually learn the cross-file dependency instead of guessing from surface patterns — the gap you saw in Step 2.
What is a file's in-degree, and why does it drive the sort?
It's how many files that file imports. In-degree 0 means it's safe to place now; every time you place a file, the files that imported it lose a blocker and their in-degree drops. Keep taking the least-blocked file and imports always land first.
Why “smallest in-degree” instead of “zero”?
Real projects have import cycles — two files needing each other — where nothing ever hits zero. Taking the least-blocked file keeps the sort moving through cycles, and behaves identically to a textbook topological sort on clean, acyclic projects.
What does Fill-in-the-Middle actually change?
It rewrites half the documents so the middle chunk sits last, after the prefix and suffix. “Predict next” becomes “fill the hole given both sides” — the infilling an editor needs. The cost: a 100% rate would hurt plain completion, so it's kept at 50%.
Where did the corpus recipe actually show up in the scores?
In the cross-file test of Step 9. Retraining without repo-level ordering drops exact-match accuracy on Java, TypeScript and C# — the languages where files lean on each other most. Single-function benchmarks miss this entirely.
What did this page deliberately skip?
The later DeepSeek machinery. This is a dense model; the mixture-of-experts routing, latent attention, and RL-for-reasoning arrive in V2, V3 and R1 — each taught on its own page. Here the whole story is the corpus and the objective.
“We attempt to organize the pre-training data at the repository level to enhance the pre-trained model's understanding capability within the context of cross-files within a repository.” — the paper, DeepSeek-AI, 2024
The open code recipe that the whole series was built on.
DeepSeek-Coder made one argument stick: a from-scratch, open, code-first model can catch the closed leaders if the corpus is built with care. That argument carried straight into the models that followed.
DeepSeek-Coder-v1.5
Restarted from the general DeepSeek-LLM 7B and kept training — trading a sliver of coding for large gains in math and language. The lesson: the best code models sit on strong general ones.
DeepSeek-V2 / V3
The open lineage that followed traded dense layers for sparse mixture-of-experts and latent attention — different machinery, each explained on its own page.
DeepSeek-R1
Reinforcement-learned reasoning, built on the same open, from-scratch conviction that started here — a topic for its own walkthrough.
The corpus was the quiet idea; the open, from-scratch stance was the loud one — and it set the tone for everything DeepSeek shipped next.