# Architecture

# Architecture

TanStack Markdown separates parsing, rendering, and optional docs behavior so each cost can be imported and measured independently.

```mermaid
flowchart LR
  M["Markdown source"] --> P["Parser"]
  P --> A["Serializable AST"]
  A --> H["HTML renderer"]
  A --> R["React renderer"]
  A --> C["JSON or content cache"]
  E["Optional extensions"] --> P
  E --> H
  X["External highlighter"] --> H
  X --> R
```

## Package boundaries

- `parser.ts` owns document normalization, definitions, block parsing, and AST creation.
- `inline.ts` owns bounded inline parsing.
- `html.ts` owns escaping and string serialization.
- `react.ts` owns React element creation and component replacement.
- `types.ts` is the shared public contract.
- `extensions/*` contains opt-in docs behavior.

The parser never imports either renderer. The renderers never import a highlighter. The core never imports docs extensions.

## Design constraints

- no runtime dependencies in parser or HTML paths
- no asynchronous work in the default path
- no random or environment-specific IDs
- plain serializable AST nodes
- raw HTML disabled unless explicitly trusted
- renderer parity for core syntax
- bounded behavior for malformed input
- generated compatibility, performance, and bundle reports

## Why focused hooks?

The extension API handles the common need to add a docs block or derive metadata without paying for a general compiler pipeline. It intentionally does not implement async plugins, arbitrary virtual files, source maps, JSX evaluation, or cross-format compilation.

That boundary is the product: use a unified or MDX stack when those capabilities are central, and use TanStack Markdown when the controlled docs renderer is enough.

## Release gates

Every release preserves profile fixtures, established CommonMark matches, selected GFM examples, HTML/React parity, corpus determinism, resilience limits, bundle budgets, documentation coverage, typechecking, and production packaging.
