winnow
Rust parser combinator library forked from nom with improved ergonomics. Build parsers by composing small parsers: alpha1 for letters, digit1 for digits, tuple for sequences, alt for alternatives. No code generation required — parsers are regular Rust functions. Used for parsing custom text formats, binary protocols, configuration files, and command output in agent data processing.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Parser library — no network exposure. Rust memory safety prevents parser buffer overflows. Community-maintained.
⚡ Reliability
Best When
You're writing a Rust parser for a custom text or binary format and want composable, type-safe combinators with excellent error messages.
Avoid When
You need grammar-based parsing for a formal language — use pest or tree-sitter for grammar-file-based parsers.
Use Cases
- • Parse custom agent data formats, log files, and configuration syntax with composable combinator parsers
- • Build binary protocol parsers for agent network communication without external parser generators
- • Parse structured text from agent LLM outputs (JSON-like formats, markdown sections) with type-safe Rust parsers
- • Implement config file parsers for agent tools using winnow's human-readable error messages for user-facing parse errors
- • Stream-parse large agent data files incrementally without loading full content into memory using winnow's streaming parsers
Not For
- • Full programming language parsers — use tree-sitter or pest for grammar-based parsing of complex languages
- • Simple regex-based extraction — if a regex suffices, winnow is overkill; use Rust's regex crate for pattern matching
- • Non-Rust code — winnow is Rust-only; use nom (Python/JS), pyparsing, or Parsec (Haskell) for other languages
Interface
Authentication
Parser library — no authentication.
Pricing
Community-maintained open source. MIT/Apache 2.0 dual license.
Agent Metadata
Known Gotchas
- ⚠ winnow parsers consume input by advancing the input position — if a parser fails partway, the input is partially consumed; use backtracking combinators (opt(), alt()) to handle partial match failures
- ⚠ The IResult type for streaming parsers differs from non-streaming — streaming parsers return Incomplete when more data is needed; non-streaming agents should use the complete module
- ⚠ winnow vs nom API differences: winnow uses &mut impl Stream trait instead of nom's &[u8] or &str — old nom code cannot be directly copy-pasted into winnow without modification
- ⚠ Error handling in winnow uses ErrMode::Backtrack vs ErrMode::Cut — using cut() past an alt() branch prevents the alt from trying the next parser; incorrect cut placement causes 'expected X' errors
- ⚠ Zero-copy parsing borrows from the input — parsers returning &str references have lifetime tied to the input string; cloning with .to_string() is needed to store results beyond input lifetime
- ⚠ winnow's streaming mode doesn't work with parsers that use take_while and check for EOF — streaming parsers must handle Incomplete by buffering more input before retrying
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for winnow.
Scores are editorial opinions as of 2026-03-06.