1. Why Batches Happen
Nobody sets out to convert hundreds of Markdown files. It arrives as an event: a team leaves Notion and takes its wiki as a folder of exports; a researcher's notes library needs to become a shareable PDF archive; an AI workspace has been generating one .md report a day for a year and now someone wants last year as documents. The single-file tools that work perfectly for everyday conversions hit a wall at scale — fifty files through a browser converter is fifty rounds of drag, export, rename.
At that point the problem changes shape. It is no longer "how do I convert this file" but "how do I convert this folder, reproducibly, without doing the same click fifty times."
2. Route 1 — The Script Loop (Free, Precise, Technical)
The classic answer is Pandoc in a loop. On any system with a shell:
for f in *.md; do pandoc "$f" -o "${f%.md}.pdf"; done
Ten files or ten thousand, the command is the same, and it is reproducible — the loop is the documentation of what was done. Python offers the same shape with more control (walking subfolders, renaming patterns, parallel processing), and Pandoc's manual covers the conversion options per format.
The honest limits: every file gets identical treatment, so anything per-file — a title from the first heading, a filename cleaned of the date prefix — means the script grows from one line into a small program. And setup is real: installing Pandoc and its PDF engine is the same friction documented in the single-file conversion guide, multiplied by the stake of running it over a whole folder. Test on a copy.
3. Route 2 — GUI Batch Converters
Between the terminal and the single-file tools sits a category of desktop batch converters: pick a folder, pick a format, run. They remove the scripting barrier and handle common cases — nested folders, filename patterns — through interfaces. The trade is less control than a script and varying output quality between tools; for one-off migrations where the files are homogeneous, they are a reasonable middle path. Check what happens to tables and code blocks specifically — this is where weaker converters quietly mangle content.
4. Route 3 — AI-Powered Desktop Processing
The newest route treats the folder not as N identical files but as N documents, each deserving treatment based on what it says. A desktop agent with folder access can convert and, in the same pass, do the things scripts cannot: title each PDF from its actual first heading, summarize a chat log before archiving it, reorganize files by what they contain, or skip and flag drafts that should not ship. This is the "local and private" model — files stay on disk while the agent works through them — and it is where the product ladder behind free Markdown tools terminates: single files free in the browser, folders on the desktop.
The trade is cost and trust. Script loops are free and deterministic; an agent is neither free nor deterministic, and for homogeneous conversions that trade makes no sense. It makes sense exactly when the batch involves judgment — the mixed folder of notes, logs, and drafts that no script can fairly treat identically.
5. Choosing in One Question
Ask: do all files deserve the same operation? Yes — script it (Route 1) or point a GUI converter at the folder (Route 2). No — each file needs judgment — that is Route 3, the desktop-agent case. The follow-up question is frequency: a one-time migration tolerates manual setup that a weekly pipeline cannot, and weekly pipelines want the script committed to version control regardless of route.
One practice applies to every route: convert a copied folder first, spot-check the output — tables, code blocks, and tables from converted pages are where conversion quality shows — and only then run it on the real thing.
6. When Folder-Scale Work Needs an Agent
The scope lines are worth drawing once, clearly. A single file with a quick edit: browser tools, free, instant. A folder of identical conversions: scripts, free, deterministic. A folder where each file needs to be understood — summarized, titled, triaged, restructured — that is agentic work, and it belongs in a desktop environment where the agent can read files locally and act across the whole set.
That progression — one file free on the web, folders on the desktop, judgment by AI — is the same product ladder showing up at the batch scale. The files were always plain text; what changes with scale is how much judgment the conversion requires.
7. What Each Route Preserves: The Quality Matrix
Route choice is usually framed as cost versus control, but the more consequential axis is what survives conversion intact. A folder can arrive with perfect filenames and shredded tables, or clean tables and no trace of its metadata. The matrix compares the three routes on the six things that most often decide whether a converted folder is usable.
| What you care about | Pandoc script | GUI batch converter | AI desktop agent |
|---|---|---|---|
| Table fidelity | High — standard pipe tables convert cleanly; exotic layouts depend on the output format | Varies by tool; simple tables usually survive, wide tables can clip | Reads table structure and can rebuild it, though every rebuild is a chance to alter a cell |
| Code blocks | Preserved verbatim; PDF output needs a highlighting or line-wrap setup | Usually preserved; pagination can split long lines | Preserved, and can be reflowed or reformatted on request |
| Frontmatter (YAML) | Parsed as document metadata — kept out of the visible output unless the template emits it | Frequently emitted as literal text or silently dropped | Read and understood; can be carried into filenames, titles, or a manifest |
| Image links | Resolved relative to each file, which works when paths are intact | Mixed record; some tools lose relative paths | Can test every link against the disk and repair the broken ones |
| Subfolders | One find or glob away | Usually built into the folder picker | Built in |
| Cost | Free | Free to cheap, per tool | Subscription or metered usage |
Two readings are worth making explicit. Scripts are strongest exactly where the stakes are highest — code fidelity and deterministic image resolution — which is why they stay the default for homogeneous folders despite the setup cost. The frontmatter row is the quiet trap: Pandoc treats YAML as input metadata rather than content, so a script that works can still strip every title and tag from the visible output, and GUI tools are unpredictable enough that the safe assumption is that metadata will not survive. No row has a single winner — which is the argument for picking the route by the row you cannot afford to lose, not by the price tag.
8. Frontmatter, Filenames, and the Manifest
The most common way a batch conversion fails quietly is not mangled tables — it is metadata loss. A folder whose files open with a YAML front matter block (the --- fence carrying title, date, and tags — standard syntax covered in any Markdown cheat sheet) can come out the other side with that block gone, pasted into the body as literal text, or present but unreadable to whatever receives the files. The loss is invisible at a glance, so it surfaces weeks later, when someone searches for a tag that no longer exists.
The fix is a decision, made before the run, about which of three fates the front matter should meet. It can drive the output: Pandoc templates pull title: into PDF metadata and HTML <title> tags, and scripts can sort files by date: or tags:. It can survive visibly in HTML's document head, which PDF has nowhere to show. Or it can be captured on the side, by a pre-pass that greps the YAML block into a CSV kept next to the output. The wrong answer is not choosing, which is what happens by default.
The companion practice is the manifest — the batch converter's insurance policy. Before touching anything, record the inventory: find . -name "*.md" -printf "%p\t%s\n" > manifest.txt captures every path and byte size, and a second column can map each source to its renamed output. The manifest is what turns an interrupted run into a resumable one and a rename pass into a reversible one. Markdown is plain text, so the inventory of a thousand files costs kilobytes. Filenames deserve the same discipline: spaces, CJK characters, and date prefixes survive conversion, but renaming three hundred files by hand mid-migration is where folders get lost — so change names through a manifest mapping, never by editing the only copy in place.
9. A Failure-Mode Gallery
Every bulk conversion produces failures, and the same three modes account for most of them. None are exotic; each has a recognizable signature and a mechanical repair. Reading them before the first real run is cheaper than discovering them at file 214 of 300.
The run that stopped halfway
The symptom is an output folder holding 214 files when the manifest lists 300 — some of them zero-byte or truncated, because the process died mid-write — a Ctrl-C, a reboot, a crashed engine. Prevention is structural: write to a separate output folder, write each file atomically to a temp name before moving, and log every success. The repair: delete the zero-byte outputs and re-run with a skip-existing guard ([ -f out.pdf ] || pandoc ...) — the failed run becomes a checkpoint, not a restart.
The encoding that arrived as mojibake
The symptom is content that opens as garbage of a specific flavor: 客户部署项目 rendering as 瀹㈡埛閮ㄧ讲椤圭洿 — UTF-8 bytes read through a GBK lens, or the reverse. It happens because Pandoc assumes UTF-8 input, while files from legacy Chinese Windows tools, older editors, and some chat apps are still GBK or GB18030. Prevention is a pre-pass that detects each file's encoding and normalizes everything to UTF-8 first, so the converter never guesses. If the original GBK files are intact, re-run normalization from them; bytes re-saved after a misread are damaged beyond repair, and only a backup restores them — one more argument for converting copies.
The images that stayed behind
The symptom is text that converts beautifully while every image is a blank box, or a PDF build spewing "could not fetch resource" warnings — the signature of a relative reference like ../assets/diagram.png orphaned when the file was converted away from its assets folder. Prevention is positional: convert in place, or point Pandoc's --resource-path at the original tree, and keep the assets folder adjacent to the output. The repair is to check broken references against the manifest, restore the adjacency the files expected, and re-run — the paths were never wrong, they were orphaned.
10. The Verification Pass
A run is not finished when the progress bar empties; it is finished when the output has been checked against the input. Four checks take minutes on a few hundred files and catch essentially everything in the gallery above. Converting a copy and verifying it should be one motion, not two.
- Counts align. Source
.mdfiles, including subfolders, equal outputs — compared directly against the manifest. - First and last lines read. Sampled files open with the expected heading and end where their sources end, exposing truncation counts cannot see.
- Image references resolve. Counting
![occurrences and confirming each target exists on disk is one script, and it catches orphaned assets instantly. - Five random files, read in full. Five random outputs are opened beside their sources and actually read.
The last check is the one people skip, and it is the only one that catches semantic damage: reordered sections, a table that became paragraphs, a code block that absorbed the paragraph after it. Counts validate the envelope; only reading validates the content. For a recurring pipeline, script all four; for a one-off, do them by hand — fifteen minutes of reading is the cheapest insurance in the workflow.
11. Source Check: Notion and Obsidian Exports
Most real batches are migration batches, and the two most common sources are Notion and Obsidian. Both hand you a folder of Markdown, but each arrives with its own habits. Notion's Markdown & CSV export produces one .md file per page, a full-page database exports as a CSV plus a separate Markdown file for each subpage, and callout blocks become raw HTML because no Markdown equivalent exists, according to Notion's export documentation (as of September 2026). Three consequences follow. Comments survive only in HTML exports, so an archive that needs discussion threads needs the HTML format for them. Every filename carries a 32-character page ID suffix — plan a manifest-driven rename pass. And on Windows, keeping "create folders for subpages" enabled can push paths past the 260-character limit where Explorer fails to unzip; disable the option or extract with 7-Zip. The page content itself migrates well, being structurally close to Markdown note-taking, once those edge cases are handled.
An Obsidian vault needs no export step at all, because a vault already is a folder of plain .md files — copying the folder is the export. What needs attention is link syntax: [[wikilinks]] are an Obsidian convention rather than standard Markdown, and converters outside Obsidian pass them through as literal text, leaving every cross-reference broken. For links going forward, the fix is a setting — disabling "Use [[Wikilinks]]" under Files and links and choosing relative-path format, per Obsidian's documentation (as of September 2026); for links already written, community plugins batch-convert wikilinks in place before the folder meets any converter. Attachments deserve one glance too: relative-path subfolders are what let images follow the notes out of the vault — and into an AI agent workflow over the same folder later.
12. Three Folders, Three Routes: 30, 300, 3,000
The trade-offs become concrete at specific sizes, so it helps to walk three composite folders that cover most real cases between them. The right route changes with the count. So does the cost of being wrong.
30 files — the one-off folder
A consultant inherits thirty meeting notes that must become PDFs once, for a client who does not use Markdown. A GUI batch converter pointed at the folder, or a single Pandoc loop typed once, finishes in minutes — at this size the route matters less than the verification pass. The mistake is over-engineering: a parameterized pipeline with encoding pre-passes is wasted on thirty identical conversions. Convert a copy, run the four checks, ship, and archive the manifest with the output.
300 files — the mixed library
At three hundred files the folder shows texture: subfolders, date-prefixed names, one or two files in the wrong encoding that will poison a naive loop. This is where the script route pays for its setup cost, because loop plus manifest plus separate output directory plus encoding pre-pass together form a run that can be stopped, inspected, and resumed. A GUI tool copes, but per-file exceptions are where clicks stop scaling — every "except this one" becomes a manual round trip. The script is also the artifact that survives: next quarter's export needs edits, not a rebuild.
3,000 files — the pipeline
At three thousand, this is not a task but a small system: idempotency that skips already-converted files, parallel workers, checksum-based verification against the manifest, and the script itself in version control. Uploading three thousand documents to a cloud converter is a different decision than uploading one — the privacy question about where files go becomes a stakeholder conversation at this scale, and local processing dominates here for that reason. If the files need identical treatment, the answer is still a script — a bigger, better-instrumented one. If they need judgment — triage, summaries, per-document restructuring — this is where AI pipelines over Markdown folders earn their cost and the desktop-agent route stops being a luxury.
13. Conclusion
Batch conversion is not one problem but a family: identical conversions belong to scripts, one-off migrations to GUI converters, and judgment-heavy folders to local agents. All three start from the same place — a folder of portable .md files whose content outlives whichever tool processes them.
Before choosing a route, open three files from the folder and ask what they have in common. The answer picks the tool.
https://floatboat.ai/blog/batch-convert-markdown-files
