Split DOCX and PDF documents by headings while keeping their original format and styling.
Install the npm or Python package; both provide the same doc-splitter command.
Installation · Usage · API · Development · Security
Doc Splitter turns structured DOCX and PDF documents into smaller files at their heading boundaries. Each output remains in the source format and is derived from a complete copy of the original document, preserving the formatting and styling of the retained content.
Choose either the TypeScript or Python package. You do not need to install both.
Requires Node.js 24 or newer:
npm install --global @polishedapps/doc-splitterRequires Python 3.11 or newer:
python -m pip install doc-splitterBoth installations provide the doc-splitter command:
doc-splitter --helpOpen a document and display its extracted heading hierarchy without calculating output paths or writing files:
doc-splitter inspect <input.docx|input.pdf> [--json]
doc-splitter inspect "manual.docx"Calculate the exact output filenames and document ranges without creating them:
doc-splitter plan <input.docx|input.pdf> [split options] [--json]
doc-splitter plan "manual.docx" --level 2 --parent-headings foldersPlan and create the output documents. The split workflow does not require a split command word:
doc-splitter <input.docx|input.pdf> [options]
Split a DOCX document at level 1:
doc-splitter "manual.docx" --level 1 --output ".\output"Split a PDF document at level 2:
doc-splitter "book.pdf" --level 2 --output ".\chapters"Paths containing spaces or Unicode characters can be quoted normally:
doc-splitter "C:\Documents\manual.pdf" --output "C:\Documents\Split Files"Split options apply to both plan and the default split workflow. --output, --subfolder, and --yes apply only when creating files.
| Option | Description |
|---|---|
--output <directory> |
Write the split documents to the selected directory. |
--subfolder |
Create a unique source-named directory inside the output directory. |
--level <number> |
Split at the selected heading level. |
--parent-headings <none|filename|folders> |
Omit parent headings, include them in filenames, or create parent folders. |
--index / --no-index |
Include or omit indexes in output filenames. |
--title-case / --no-title-case |
Transform or preserve heading-name casing. |
--original-name |
Prefix output filenames with the input filename. |
--multilevel-index |
Use hierarchical indexes in output filenames. |
--yes |
Create the planned files without asking for confirmation. |
--json |
Return a versioned JSON response. Splitting also requires --yes. |
--quiet |
Suppress progress and nonessential human-readable output. |
The input document is never modified. Existing output files are not overwritten.
The npm package also exposes the TypeScript inspect-plan-execute API:
import {
DEFAULT_SPLIT_OPTIONS,
executeSplit,
inspectDocument,
planSplit,
} from "@polishedapps/doc-splitter";
const inspected = await inspectDocument("manual.docx");
if (!inspected.ok) throw new Error(inspected.error.message);
const planned = planSplit(inspected.value, DEFAULT_SPLIT_OPTIONS);
if (!planned.ok) throw new Error(planned.error.message);
const executed = await executeSplit(inspected.value, planned.value, {
selectedOutputDirectoryPath: "./output",
outputDirectoryMode: "direct",
});
if (!executed.ok) throw new Error(executed.error.message);inspectDocument reads and retains the input snapshot, planSplit calculates filenames and document ranges, and executeSplit creates the planned outputs.
The Python import name is doc_splitter. Its API follows the same inspect-plan-execute workflow:
from doc_splitter import (
DEFAULT_SPLIT_OPTIONS,
execute_split,
inspect_document,
plan_split,
)
inspection = inspect_document("manual.docx")
plan = plan_split(inspection, DEFAULT_SPLIT_OPTIONS)
result = execute_split(
inspection,
plan,
"./output",
output_directory_mode="direct",
)
print(f"Created {result.created_files} files.")Both APIs retain the inspected input bytes for planning and execution. Python raises DocSplitterError for document, planning, or output failures.
Doc Splitter splits at heading boundaries without rebuilding the selected content in a blank document. This keeps each output in the original document format and preserves the formatting and styling of its retained content.
- Supported inputs are
.docxand.pdf, matched case-insensitively. - DOCX ranges use top-level Open XML body-element indexes.
- PDF ranges use zero-based page indexes.
- Split ranges include the start and exclude the end.
- Heading text is whitespace-normalized before use in filenames.
- Unsafe filename characters are removed or replaced.
- Windows reserved device names receive a trailing
_. - Outputs retain the source document format, formatting, and styling.
- Each output begins with a complete source-derived document and removes content outside its planned range.
When a document begins with exactly one level-1 heading followed by lower-level headings, Doc Splitter omits that single top heading from the returned hierarchy and promotes its descendants by one level. Content before the first returned heading can become a cover output.
doc-splitter/
├─ README.md
├─ LICENSE
├─ assets/
├─ test-data/
├─ typescript/
│ ├─ package.json
│ ├─ src/
│ └─ tests/
├─ python/
│ ├─ pyproject.toml
│ ├─ src/doc_splitter/
│ └─ tests/
└─ .github/workflows/
test-data/ contains versioned DOCX and PDF inputs, SHA-256 hashes, extraction expectations, filename rules, and split-planning cases shared by the tests.
Run from typescript/:
npm ci
npm run checkRun from python/:
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"
python -m compileall -q src
python -m pytestGenerated split documents belong in temporary directories or .artifacts/, not in test-data/. If a committed fixture changes intentionally, update its SHA-256 and affected expectations in the same change.
Report security vulnerabilities privately as described in SECURITY.md. Do not include document contents, credentials, API tokens, or other sensitive data in a public issue.