Overview
Streaming mode enables incremental parsing of markdown content as it arrives, making it ideal for processing LLM outputs or any scenario where content is generated progressively. The parser maintains internal state across calls and only returns blocks that have been finalized.When streaming is disabled (default), the parser finalizes all open blocks at the end of the input. With streaming enabled, blocks are only emitted once they become stable and closed.
How streaming works
The parser implements streaming by tracking which blocks are “closed” versus “open”:- Closed blocks: Fully parsed and stable, ready to be emitted
- Open blocks: Still being built, may change as more content arrives
- A blank line after a paragraph
- A closing fence for a code block
- New block-level content that can’t continue the current block
Internal implementation
The parser uses anisClosed flag on each internal block node to track state (see markdown-parser.ts:42-44):
closeRightmostPath function walks the rightmost child chain and marks all open blocks as closed before returning.
Basic usage
- Complete parsing
- Streaming mode
When to use streaming
LLM outputs
Process AI-generated markdown as it streams from the model, providing real-time rendering
Network streams
Parse markdown content arriving over HTTP streams or WebSockets without buffering
Large files
Process large markdown files chunk by chunk to reduce memory usage
Real-time editing
Update parsed output as users type without re-parsing the entire document
Block closure rules
Different block types close under different conditions:Paragraphs and tables
Paragraphs and tables
Close when encountering:
- A blank line
- The start of another block element (heading, code block, etc.)
Fenced code blocks
Fenced code blocks
Close when encountering a closing fence with the same marker and at least as many characters:
Indented code blocks
Indented code blocks
Close when encountering a non-indented, non-empty line:
HTML blocks
HTML blocks
Close based on their specific end pattern or blank line interruption:
Headings and thematic breaks
Headings and thematic breaks
Always closed immediately upon creation (single-line elements):
Link reference definitions
From the README:CommonMark specification allows link reference definitions to appear after the links that use them. Therefore, when streaming is enabled, it is important to consider that a link reference might not resolve, since its definition could arrive in a later chunk of the input.The parser only processes reference definitions for finalized blocks (see
markdown-parser.ts:519-553):
State management
The parser maintains state across streaming calls using:- Root node: Contains all parsed blocks (see
markdown-parser.ts:13-18) - Next node index: Tracks which blocks have been emitted (see
markdown-parser.ts:19) - Reference definitions: Stores link references across chunks (see
markdown-parser.ts:20-21) - Line splitter: Handles line boundaries across chunks (see
markdown-parser.ts:13)
Performance considerations
Memory usage: Streaming mode keeps internal state for open blocks, but emits and discards closed blocks, preventing unbounded memory growth. Latency: Blocks are emitted as soon as they close, minimizing delay between input and output. Incremental processing: The line-by-line parsing approach (seemarkdown-parser.ts:25-27) ensures minimal reprocessing:
Best practices
Create a single parser instance
Reuse the same
MarkdownParser instance across streaming calls to maintain state:Finalize with stream: false
Always call with
stream: false at the end to close remaining open blocks: