← Blog

How to Chunk Long Documents for Claude API

2026-11-04 · 5 min read · SubToAPI Team

When a document is too large to fit in a single Claude API request — or too large to process cost-effectively in one call — you need to split it into chunks that preserve meaning, fit within context limits, and still produce coherent output when reassembled. The right approach depends on document type (prose, code, tables, transcripts) and what you're doing with the output (summarization, extraction, Q&A, translation).

The short answer: don't chunk by raw character count alone. Chunk by semantic boundaries (paragraphs, sections, headings) with a target token budget per chunk, add a small overlap between chunks for context continuity, and carry forward a compact "memory" of prior chunks when the task requires cross-chunk coherence (like summarizing a 200-page report). Below is a practical breakdown of how to do this correctly.

Why Chunking Matters Even With Large Context Windows

Claude's models support large context windows, but that doesn't mean you should always send the whole document in one shot:

Chunking isn't just a workaround for context limits — it's often the better engineering choice even when the whole document would technically fit.

Step 1: Pick a Chunking Strategy Based on Document Structure

Fixed-size chunking (e.g., every 2,000 tokens) is the simplest but worst option for quality — it cuts sentences and sections mid-thought.

Structure-aware chunking respects natural boundaries:

Recursive chunking is a good default: try to split on the largest structural unit (section), and if that's still too big, recursively split on the next level down (paragraph, then sentence).

function chunkText(text, maxTokens = 1500) {
  const sections = text.split(/\n(?=#{1,3} )/); // split on markdown headings
  const chunks = [];

  for (const section of sections) {
    if (estimateTokens(section) <= maxTokens) {
      chunks.push(section);
    } else {
      // recurse into paragraphs
      const paragraphs = section.split('\n\n');
      let buffer = '';
      for (const p of paragraphs) {
        if (estimateTokens(buffer + p) > maxTokens) {
          chunks.push(buffer);
          buffer = p;
        } else {
          buffer += '\n\n' + p;
        }
      }
      if (buffer) chunks.push(buffer);
    }
  }
  return chunks;
}

function estimateTokens(str) {
  return Math.ceil(str.length / 4); // rough heuristic, ~4 chars per token
}

This heuristic is approximate — for production use, run a real tokenizer count before finalizing chunk sizes, since underestimating can cause requests to exceed limits.

Step 2: Add Overlap Between Chunks

If a sentence or idea spans a chunk boundary, the model processing chunk N+1 has no idea what came right before it. A 10–15% overlap (by token count) between consecutive chunks fixes most of this:

function addOverlap(chunks, overlapTokens = 150) {
  return chunks.map((chunk, i) => {
    if (i === 0) return chunk;
    const prevTail = chunks[i - 1].slice(-overlapTokens * 4); // ~4 chars/token
    return prevTail + '\n\n' + chunk;
  });
}

Overlap matters most for summarization and extraction tasks. It matters less for strict Q&A over isolated sections where bleed-through context could actually confuse the answer.

Step 3: Decide How to Reassemble Output

Chunking the input is half the problem — you also need a strategy for combining outputs:

Pick based on the task. Don't use rolling context for simple extraction — it adds cost and latency with no quality benefit.

Step 4: Build the Pipeline Around Claude API Calls

Once chunks are ready, each one becomes a request. If you're calling Claude through SubToAPI, the pattern looks like this:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Summarize this section:\n\n" }
    ]
  }'

For map-reduce pipelines, run chunk requests in parallel to cut total processing time, then make a final call with the combined summaries. SubToAPI gives each application its own sub_live_... key with usage metadata per request, which makes it straightforward to track token consumption across a chunked batch job and see exactly where your cost is going — useful when you're debugging whether your chunk size is too large or your overlap is too generous. See /docs/messages for request formatting and /docs/streaming if you're streaming per-chunk responses back to a UI as they complete.

Practical Chunk Size Guidelines

Questions

Does Claude have a hard document size limit I need to chunk around? Yes — every model has a maximum context window measured in tokens, and that limit includes both your input and the expected output. Check the current limits for your model before assuming a document fits in one call.

Should I always use overlap between chunks? No. Overlap helps when meaning spans chunk boundaries (summarization, narrative text), but it's unnecessary and wasteful for independent extraction tasks where each chunk is self-contained, like pulling line items from separate invoice pages.

How do I know if my chunks are too large? If output quality drops on long chunks (details from the middle get skipped or summaries feel shallow), reduce chunk size. Test with a fixed document and compare output quality at 1,000, 2,000, and 4,000-token chunk sizes to find the sweet spot for your use case.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →