ai-architecture
guide
19 Oct 2026
Six ways to chunk one document, and the markdown aware one that cut the most code
The splitter configured for markdown broke 18 fenced code blocks. The generic one broke 5. The setting is not doing what its name suggests, and the separator list says why.
By Purvansh Parmar
Checked 2026-10-21
Read 8 min
Entries 6
Chunking comparisons usually report how many chunks each splitter made and how long they were. That tells you almost nothing. What costs you at retrieval time is structural damage: half a code block is a chunk that is wrong on its own and wrong as a neighbour, and a chunk starting mid sentence has lost the subject of its own first clause. So I scored six splitters on damage instead of on counts, and the one with markdown in its configuration came last on the metric you would most expect it to win.
How this was checkedSplit the same 16,494 token technical document six ways and scored each result on what it broke rather than on how many pieces it made. The splitter told to use markdown separators cut 18 of the document's 30 fenced code blocks, against 5 for the generic recursive splitter. Reading the separator list explains it: the markdown preset ranks the code fence as its second highest priority split point, so it is actively choosing to cut there.
What I compared on
- fenced code blocks cut in half, which is the damage that cannot be repaired downstream
- share of chunks ending mid sentence
- whether chunk size stays inside the budget you set
Splits on paragraph breaks first, then lines, then spaces, falling through the list until a chunk fits.
Wins
It is the default for a reason. Falling through paragraph, then line, then word gives it natural boundaries without any knowledge of the format, and it never once exceeded the size budget.
Loses
It has no idea what a code block is, so the five it cut were cut blindly, and nothing in its output flags which chunks are damaged. On prose with no structure it is identical to a fixed window.
5 code blocks cut11 percent mid sentence89 chunks
Ignores size entirely and splits only at headings, attaching the heading path to each chunk as metadata.
Wins
It is the only splitter that did no structural damage at all, and the heading path it attaches is genuinely useful context that every other option here throws away.
Loses
A 7,447 token chunk does not fit in most embedding windows and will be silently truncated by whatever you hand it to. Size is not a parameter, so you cannot ask it to behave, you can only run a second splitter over it's output.
0 code blocks cutmax 7,447 tokens12 chunks
Encodes the document once and cuts every 250 tokens with 50 of overlap, counting in the model's own units.
Wins
It is the only splitter whose output size you can actually predict, with a spread of 24 tokens between median and maximum against 171 for the recursive splitter. If you are packing a fixed context budget, this is the one that makes the arithmetic work.
Loses
It respects nothing except the token count, so three quarters of its chunks stop in the middle of a sentence and it cut almost a third of the document's code blocks.
max 230 tokens9 code blocks cut73 percent mid sentence
The same recursive splitter with the separator list swapped for markdown's, which is the obvious choice for markdown.
Wins
It splits cleanly at headings, which is the behaviour people want from it, and the heading boundary is the highest priority separator in the list.
Loses
The second highest priority separator in that list is the code fence itself, so it actively prefers to cut at the start or end of a code block. That is a defensible way to separate prose from code and a bad surprise if you assumed the preset protected code.
18 code blocks cut3.6x the generic splitterfence is separator 2 of 9
Cut every thousand characters with no regard for any boundary at all, the baseline everything else improves on.
Wins
It produced the fewest chunks and the highest median size of the bounded splitters, so it wastes the least space on overlap and the least on boundary padding.
Loses
83 percent of chunks end mid sentence, frequently mid word. Every one of those is an embedding of a fragment whose meaning depends on text that is in a different chunk.
83 percent mid sentence67 chunks6 code blocks cut
The same blind cut with two hundred characters of overlap bolted on, which is the usual advice for fixing it.
Wins
The overlap does genuinely help the retrieval case it is meant for: a fact sitting exactly on a boundary now appears whole in one of the two neighbours rather than in neither.
Loses
It made both damage measures slightly worse while costing 25 percent more chunks, because overlap adds boundaries rather than aligning them. It is a patch over blind splitting, not a fix for it.
89 percent mid sentence25 percent more chunks7 code blocks cut
Side by side
| Chunks | Median tok | Max tok | Code cut | Mid sentence |
| Recursive, generic | 89 | 208 | 379 | 5 | 11% |
| Markdown headers | 12 | 339 | 7,447 | 0 | 0% |
| Token window | 103 | 206 | 230 | 9 | 73% |
| Recursive, markdown preset | 100 | 196 | 349 | 18 | 14% |
| Fixed chars | 67 | 238 | 386 | 6 | 83% |
| Fixed chars + overlap | 84 | 238 | 375 | 7 | 89% |
Verdict
Use the Recursive character splitter with its generic separators, and do not reach for the markdown preset just because your documents are markdown. The preset cut 18 code blocks to the generic splitter's 5. The reason is in its separator list: the code fence ranks second of nine, so cutting there is the behaviour it was configured for rather than an accident. If your corpus is mostly code samples, run the Markdown header splitter first to get clean structural units with their heading path attached, then run the recursive splitter over any unit that came out too large. That gets you the only zero damage result in the table without the 7,447 token chunk that makes it unusable on its own.
Sources