As Markdown increasingly arrives live as a stream in chat apps, terminals, coding agents, and other interfaces, full-document Markdown parsing has become a performance bottleneck, causing CPU spikes and UI lag. Many UIs attempt to handle this by repeatedly re-parsing and re-rendering the entire growing document, as output gets longer, this causes severe memory churn and layout thrashing. A streaming parser can keep a small input window, emit safe output, and discard old text.
I have found little guidance for live Markdown generators and renderers: which features should they avoid, and which need buffering or lookahead? Would a short guide help?
I have been trying this in mdflow, a Markdown-to-terminal streaming renderer.
Its parser is a streaming rework of MD4C. MD4C is fully CommonMark-compliant; mdflow is tested against it and documents its streaming limits. The terminal presentation is outside CommonMark’s scope; this is only about parsing.
mdflow emits incrementally, usually a line at a time, while buffering at most two input lines. The remaining limits mostly affect static documents, because live streams rarely use these features:
- Reference links cannot fully stream because definitions may appear later.
- Multi-line Setext headings and tight/loose lists need a little lookahead or a small compromise.
- Most other constructs can be processed as input arrives; GFM is mostly covered too.
The memory benefit may be large. In the current 10 MB mixed-Markdown benchmark, mdflow peaks at 2.3 MB, versus 102.3 MB for mdcat and 972.8 MB for glow. The README has the details.
I don’t have any proposal for this, be it subset, parser extensions, authoring guidelines, or something else entirely. I simply want to share the observation that the gap between standard Markdown and full streamability is small. Resolving those few lookahead constraints opens up massive performance gains.
mdflow and this idea are early experiments. I am not a long-time Markdown implementer and would welcome corrections.
Special thanks to @mity for creating MD4C. Its flat-buffer design made this streaming reconstruction practical.