<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Na'aman Hirschfeld (Goldziher)</title>
    <description>The latest articles on Forem by Na'aman Hirschfeld (Goldziher) (@nhirschfeld).</description>
    <link>https://forem.com/nhirschfeld</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988181%2F7b5f3fb2-879a-4b49-927a-587fdfb76ade.jpeg</url>
      <title>Forem: Na'aman Hirschfeld (Goldziher)</title>
      <link>https://forem.com/nhirschfeld</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nhirschfeld"/>
    <language>en</language>
    <item>
      <title>Kreuzberg v4.0.0-RC.8 is Available</title>
      <dc:creator>Na'aman Hirschfeld (Goldziher)</dc:creator>
      <pubDate>Mon, 15 Dec 2025 13:06:14 +0000</pubDate>
      <link>https://forem.com/kreuzberg/kreuzberg-v400-rc8-is-available-4fma</link>
      <guid>https://forem.com/kreuzberg/kreuzberg-v400-rc8-is-available-4fma</guid>
      <description>&lt;p&gt;Hi Peeps,&lt;/p&gt;

&lt;p&gt;I'm excited to announce that &lt;a href="https://github.com/kreuzberg-dev/kreuzberg" rel="noopener noreferrer"&gt;Kreuzberg&lt;/a&gt; v4.0.0 is coming very soon. We will release v4.0.0 at the beginning of next year - in just a couple of weeks time. For now, v4.0.0-rc.8 has been released to all channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Kreuzberg?
&lt;/h2&gt;

&lt;p&gt;Kreuzberg is a document intelligence toolkit for extracting text, metadata, tables, images, and structured data from 56+ file formats. It was originally written in Python (v1-v3), where it demonstrated strong performance characteristics compared to alternatives in the ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's new in V4?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A Complete Rust Rewrite with Polyglot Bindings
&lt;/h3&gt;

&lt;p&gt;The new version of Kreuzberg represents a massive architectural evolution. &lt;strong&gt;Kreuzberg has been completely rewritten in Rust&lt;/strong&gt; - leveraging Rust's memory safety, zero-cost abstractions, and native performance. The new architecture consists of a high-performance Rust core with native bindings to multiple languages. That's right - it's no longer just a Python library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kreuzberg v4 is now available for 7 languages across 8 runtime bindings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rust&lt;/strong&gt; (native library)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt; (PyO3 native bindings)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; - Node.js (NAPI-RS native bindings) + Deno/Browser/Edge (WASM)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruby&lt;/strong&gt; (Magnus FFI)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java 25+&lt;/strong&gt; (Panama Foreign Function &amp;amp; Memory API)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt; (P/Invoke)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; (cgo bindings)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Post v4.0.0 roadmap includes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Elixir (via Rustler - with Erlang and Gleam interop)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, it's available as a &lt;strong&gt;CLI&lt;/strong&gt; (installable via &lt;code&gt;cargo&lt;/code&gt; or &lt;code&gt;homebrew&lt;/code&gt;), &lt;strong&gt;HTTP REST API server&lt;/strong&gt;, &lt;strong&gt;Model Context Protocol (MCP) server&lt;/strong&gt; for Claude Desktop/Continue.dev, and as &lt;strong&gt;public Docker images&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the Rust Rewrite? Performance and Architecture
&lt;/h3&gt;

&lt;p&gt;The Rust rewrite wasn't just about performance - though that's a major benefit. It was an opportunity to fundamentally rethink the architecture:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architectural improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-copy operations&lt;/strong&gt; via Rust's ownership model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;True async concurrency&lt;/strong&gt; with Tokio runtime (no GIL limitations)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming parsers&lt;/strong&gt; for constant memory usage on multi-GB files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SIMD-accelerated text processing&lt;/strong&gt; for token reduction and string operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory-safe FFI boundaries&lt;/strong&gt; for all language bindings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugin system&lt;/strong&gt; with trait-based extensibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  v3 vs v4: What Changed?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;v3 (Python)&lt;/th&gt;
&lt;th&gt;v4 (Rust Core)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pure Python&lt;/td&gt;
&lt;td&gt;Rust 2024 edition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File Formats&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30-40+ (via Pandoc)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;56+ (native parsers)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python only&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;7 languages&lt;/strong&gt; (Rust/Python/TS/Ruby/Java/Go/C#)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires Pandoc (system binary)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Zero system dependencies&lt;/strong&gt; (all native)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Embeddings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;✓ FastEmbed with ONNX (3 presets + custom)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semantic Chunking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Via semantic-text-splitter library&lt;/td&gt;
&lt;td&gt;✓ Built-in (text + markdown-aware)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token Reduction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in (TF-IDF based)&lt;/td&gt;
&lt;td&gt;✓ Enhanced with 3 modes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional (fast-langdetect)&lt;/td&gt;
&lt;td&gt;✓ Built-in (68 languages)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Keyword Extraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional (KeyBERT)&lt;/td&gt;
&lt;td&gt;✓ Built-in (YAKE + RAKE algorithms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OCR Backends&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tesseract/EasyOCR/PaddleOCR&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Same + better integration&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plugin System&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited extractor registry&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Full trait-based&lt;/strong&gt; (4 plugin types)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Tracking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Character-based indices&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Byte-based with O(1) lookup&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Servers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;REST API (Litestar)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;HTTP (Axum) + MCP + MCP-SSE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Installation Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~100MB base&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16-31 MB complete&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python heap management&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RAII with streaming&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Concurrency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;asyncio (GIL-limited)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tokio work-stealing&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Replacement of Pandoc - Native Performance
&lt;/h3&gt;

&lt;p&gt;Kreuzberg v3 relied on &lt;strong&gt;Pandoc&lt;/strong&gt; - an amazing tool, but one that had to be invoked via subprocess because of its GPL license. This had significant impacts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v3 Pandoc limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System dependency (installation required)&lt;/li&gt;
&lt;li&gt;Subprocess overhead on every document&lt;/li&gt;
&lt;li&gt;No streaming support&lt;/li&gt;
&lt;li&gt;Limited metadata extraction&lt;/li&gt;
&lt;li&gt;~500MB+ installation footprint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;v4 native parsers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero external dependencies&lt;/strong&gt; - everything is native Rust&lt;/li&gt;
&lt;li&gt;Direct parsing with full control over extraction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Substantially more metadata&lt;/strong&gt; extracted (e.g., DOCX document properties, section structure, style information)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming support&lt;/strong&gt; for massive files (tested on multi-GB XML documents with stable memory)&lt;/li&gt;
&lt;li&gt;Example: PPTX extractor is now a &lt;strong&gt;fully streaming parser&lt;/strong&gt; capable of handling gigabyte-scale presentations with constant memory usage and high throughput&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  New File Format Support
&lt;/h3&gt;

&lt;p&gt;v4 expanded format support from ~20 to &lt;strong&gt;56+ file formats&lt;/strong&gt;, including:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Added legacy format support:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.doc&lt;/code&gt; (Word 97-2003)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.ppt&lt;/code&gt; (PowerPoint 97-2003)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.xls&lt;/code&gt; (Excel 97-2003)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.eml&lt;/code&gt; (Email messages)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.msg&lt;/code&gt; (Outlook messages)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Added academic/technical formats:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LaTeX (&lt;code&gt;.tex&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;BibTeX (&lt;code&gt;.bib&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Typst (&lt;code&gt;.typ&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;JATS XML (scientific articles)&lt;/li&gt;
&lt;li&gt;DocBook XML&lt;/li&gt;
&lt;li&gt;FictionBook (&lt;code&gt;.fb2&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;OPML (&lt;code&gt;.opml&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Better Office support:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XLSB, XLSM (Excel binary/macro formats)&lt;/li&gt;
&lt;li&gt;Better structured metadata extraction from DOCX/PPTX/XLSX&lt;/li&gt;
&lt;li&gt;Full table extraction from presentations&lt;/li&gt;
&lt;li&gt;Image extraction with deduplication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  New Features: Full Document Intelligence Solution
&lt;/h3&gt;

&lt;p&gt;The v4 rewrite was also an opportunity to close gaps with commercial alternatives and add features specifically designed for &lt;strong&gt;RAG applications and LLM workflows&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Embeddings (NEW)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastEmbed integration&lt;/strong&gt; with full ONNX Runtime acceleration&lt;/li&gt;
&lt;li&gt;Three presets: &lt;code&gt;"fast"&lt;/code&gt; (384d), &lt;code&gt;"balanced"&lt;/code&gt; (512d), &lt;code&gt;"quality"&lt;/code&gt; (768d/1024d)&lt;/li&gt;
&lt;li&gt;Custom model support (bring your own ONNX model)&lt;/li&gt;
&lt;li&gt;Local generation (no API calls, no rate limits)&lt;/li&gt;
&lt;li&gt;Automatic model downloading and caching&lt;/li&gt;
&lt;li&gt;Per-chunk embedding generation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;kreuzberg&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ExtractionConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmbeddingConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmbeddingModelType&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ExtractionConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;EmbeddingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EmbeddingModelType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balanced&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kreuzberg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# result.embeddings contains vectors for each chunk
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. &lt;strong&gt;Semantic Text Chunking (NOW BUILT-IN)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Now integrated directly into the core (v3 used external semantic-text-splitter library):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structure-aware chunking&lt;/strong&gt; that respects document semantics&lt;/li&gt;
&lt;li&gt;Two strategies:

&lt;ul&gt;
&lt;li&gt;Generic text chunker (whitespace/punctuation-aware)&lt;/li&gt;
&lt;li&gt;Markdown chunker (preserves headings, lists, code blocks, tables)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Configurable chunk size and overlap&lt;/li&gt;

&lt;li&gt;Unicode-safe (handles CJK, emojis correctly)&lt;/li&gt;

&lt;li&gt;Automatic chunk-to-page mapping&lt;/li&gt;

&lt;li&gt;Per-chunk metadata with byte offsets&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Byte-Accurate Page Tracking (BREAKING CHANGE)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;This is a critical improvement for LLM applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;v3&lt;/strong&gt;: Character-based indices (&lt;code&gt;char_start&lt;/code&gt;/&lt;code&gt;char_end&lt;/code&gt;) - incorrect for UTF-8 multi-byte characters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v4&lt;/strong&gt;: Byte-based indices (&lt;code&gt;byte_start&lt;/code&gt;/&lt;code&gt;byte_end&lt;/code&gt;) - correct for all string operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional page features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(1) lookup: "which page is byte offset X on?" → instant answer&lt;/li&gt;
&lt;li&gt;Per-page content extraction&lt;/li&gt;
&lt;li&gt;Page markers in combined text (e.g., &lt;code&gt;--- Page 5 ---&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Automatic chunk-to-page mapping for citations&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4. &lt;strong&gt;Enhanced Token Reduction for LLM Context&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Enhanced from v3 with three configurable modes to save on LLM costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Light mode&lt;/strong&gt;: ~15% reduction (preserve most detail)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moderate mode&lt;/strong&gt;: ~30% reduction (balanced)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggressive mode&lt;/strong&gt;: ~50% reduction (key information only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uses TF-IDF sentence scoring with position-aware weighting and language-specific stopword filtering. SIMD-accelerated for improved performance over v3.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. &lt;strong&gt;Language Detection (NOW BUILT-IN)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;68 language support with confidence scoring&lt;/li&gt;
&lt;li&gt;Multi-language detection (documents with mixed languages)&lt;/li&gt;
&lt;li&gt;ISO 639-1 and ISO 639-3 code support&lt;/li&gt;
&lt;li&gt;Configurable confidence thresholds&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  6. &lt;strong&gt;Keyword Extraction (NOW BUILT-IN)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Now built into core (previously optional KeyBERT in v3):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;YAKE&lt;/strong&gt; (Yet Another Keyword Extractor): Unsupervised, language-independent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAKE&lt;/strong&gt; (Rapid Automatic Keyword Extraction): Fast statistical method&lt;/li&gt;
&lt;li&gt;Configurable n-grams (1-3 word phrases)&lt;/li&gt;
&lt;li&gt;Relevance scoring with language-specific stopwords&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  7. &lt;strong&gt;Plugin System (NEW)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Four extensible plugin types for customization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DocumentExtractor&lt;/strong&gt; - Custom file format handlers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OcrBackend&lt;/strong&gt; - Custom OCR engines (integrate your own Python models)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostProcessor&lt;/strong&gt; - Data transformation and enrichment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validator&lt;/strong&gt; - Pre-extraction validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plugins defined in Rust work across all language bindings. Python/TypeScript can define custom plugins with thread-safe callbacks into the Rust core.&lt;/p&gt;

&lt;h4&gt;
  
  
  8. &lt;strong&gt;Production-Ready Servers (NEW)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP REST API&lt;/strong&gt;: Production-grade Axum server with OpenAPI docs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server&lt;/strong&gt;: Direct integration with Claude Desktop, Continue.dev, and other MCP clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP-SSE Transport&lt;/strong&gt; (RC.8): Server-Sent Events for cloud deployments without WebSocket support&lt;/li&gt;
&lt;li&gt;All three modes support the same feature set: extraction, batch processing, caching&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance: Benchmarked Against the Competition
&lt;/h2&gt;

&lt;p&gt;We maintain &lt;strong&gt;continuous benchmarks&lt;/strong&gt; comparing Kreuzberg against the leading OSS alternatives:&lt;/p&gt;

&lt;h3&gt;
  
  
  Benchmark Setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform&lt;/strong&gt;: Ubuntu 22.04 (GitHub Actions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Suite&lt;/strong&gt;: 30+ documents covering all formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt;: Latency (p50, p95), throughput (MB/s), memory usage, success rate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitors&lt;/strong&gt;: Apache Tika, Docling, Unstructured, MarkItDown&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Kreuzberg Compares
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Installation Size&lt;/strong&gt; (critical for containers/serverless):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kreuzberg&lt;/strong&gt;: &lt;strong&gt;16-31 MB complete&lt;/strong&gt; (CLI: 16 MB, Python wheel: 22 MB, Java JAR: 31 MB - all features included)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MarkItDown&lt;/strong&gt;: ~251 MB installed (58.3 KB wheel, 25 dependencies)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured&lt;/strong&gt;: ~146 MB minimal (open source base) - &lt;strong&gt;several GB with ML models&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docling&lt;/strong&gt;: ~1 GB base, &lt;strong&gt;9.74GB Docker image&lt;/strong&gt; (includes PyTorch CUDA)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apache Tika&lt;/strong&gt;: ~55 MB (tika-app JAR) + dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GROBID&lt;/strong&gt;: 500MB (CRF-only) to &lt;strong&gt;8GB&lt;/strong&gt; (full deep learning)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;th&gt;Formats&lt;/th&gt;
&lt;th&gt;Installation&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kreuzberg&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Fast (Rust-native)&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;56+&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16-31 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;General-purpose, production-ready&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Fast (3.1s/pg x86, 1.27s/pg ARM)&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;td&gt;7+&lt;/td&gt;
&lt;td&gt;1-9.74 GB&lt;/td&gt;
&lt;td&gt;Complex documents, when accuracy &amp;gt; size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GROBID&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡⚡ Very Fast (10.6 PDF/s)&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;td&gt;PDF only&lt;/td&gt;
&lt;td&gt;0.5-8 GB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Academic/scientific papers only&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unstructured&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Moderate&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;25-65+&lt;/td&gt;
&lt;td&gt;146 MB-several GB&lt;/td&gt;
&lt;td&gt;Python-native LLM pipelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MarkItDown&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Fast (small files)&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;11+&lt;/td&gt;
&lt;td&gt;~251 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lightweight Markdown conversion&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Apache Tika&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Moderate&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1000+&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~55 MB&lt;/td&gt;
&lt;td&gt;Enterprise, broadest format support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Kreuzberg's sweet spot:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smallest full-featured installation&lt;/strong&gt;: 16-31 MB complete (vs 146 MB-9.74 GB for competitors)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5-15x smaller&lt;/strong&gt; than Unstructured/MarkItDown, &lt;strong&gt;30-300x smaller&lt;/strong&gt; than Docling/GROBID&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust-native performance&lt;/strong&gt; without ML model overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broad format support&lt;/strong&gt; (56+ formats) with native parsers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-language support&lt;/strong&gt; unique in the space (7 languages vs Python-only for most)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production-ready&lt;/strong&gt; with general-purpose design (vs specialized tools like GROBID)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is Kreuzberg a SaaS Product?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt; Kreuzberg is and will remain &lt;strong&gt;MIT-licensed open source&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, we are building &lt;strong&gt;Kreuzberg.cloud&lt;/strong&gt; - a commercial SaaS and self-hosted document intelligence solution built &lt;em&gt;on top of&lt;/em&gt; Kreuzberg. This follows the proven open-core model: the library stays free and open, while we offer a cloud service for teams that want managed infrastructure, APIs, and enterprise features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will Kreuzberg become commercially licensed?&lt;/strong&gt; Absolutely not. There is no BSL (Business Source License) in Kreuzberg's future. The library was MIT-licensed and will remain MIT-licensed. We're building the commercial offering as a separate product around the core library, not by restricting the library itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Target Audience
&lt;/h2&gt;

&lt;p&gt;Any developer or data scientist who needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Document text extraction (PDF, Office, images, email, archives, etc.)&lt;/li&gt;
&lt;li&gt;OCR (Tesseract, EasyOCR, PaddleOCR)&lt;/li&gt;
&lt;li&gt;Metadata extraction (authors, dates, properties, EXIF)&lt;/li&gt;
&lt;li&gt;Table and image extraction&lt;/li&gt;
&lt;li&gt;Document pre-processing for RAG pipelines&lt;/li&gt;
&lt;li&gt;Text chunking with embeddings&lt;/li&gt;
&lt;li&gt;Token reduction for LLM context windows&lt;/li&gt;
&lt;li&gt;Multi-language document intelligence in production systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ideal for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAG application developers&lt;/li&gt;
&lt;li&gt;Data engineers building document pipelines&lt;/li&gt;
&lt;li&gt;ML engineers preprocessing training data&lt;/li&gt;
&lt;li&gt;Enterprise developers handling document workflows&lt;/li&gt;
&lt;li&gt;DevOps teams needing lightweight, performant extraction in containers/serverless&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison with Alternatives
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Open Source Python Libraries
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Unstructured.io&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Established, modular, broad format support (25+ open source, 65+ enterprise), LLM-focused, good Python ecosystem integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-offs&lt;/strong&gt;: Python GIL performance constraints, 146 MB minimal installation (several GB with ML models)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: Apache-2.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to choose&lt;/strong&gt;: Python-only projects where ecosystem fit &amp;gt; performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MarkItDown (Microsoft)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Fast for small files, Markdown-optimized, simple API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-offs&lt;/strong&gt;: Limited format support (11 formats), less structured metadata, ~251 MB installed (despite small wheel), requires OpenAI API for images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: MIT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to choose&lt;/strong&gt;: Markdown-only conversion, LLM consumption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Docling (IBM)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Excellent accuracy on complex documents (97.9% cell-level accuracy on tested sustainability report tables), state-of-the-art AI models for technical documents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-offs&lt;/strong&gt;: Massive installation (1-9.74 GB), high memory usage, GPU-optimized (underutilized on CPU)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: MIT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to choose&lt;/strong&gt;: Accuracy on complex documents &amp;gt; deployment size/speed, have GPU infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Open Source Java/Academic Tools
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Apache Tika&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Mature, stable, broadest format support (1000+ types), proven at scale, Apache Foundation backing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-offs&lt;/strong&gt;: Java/JVM required, slower on large files, older architecture, complex dependency management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: Apache-2.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to choose&lt;/strong&gt;: Enterprise environments with JVM infrastructure, need for maximum format coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GROBID&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Best-in-class for academic papers (F1 0.87-0.90), extremely fast (10.6 PDF/sec sustained), proven at scale (34M+ documents at CORE)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-offs&lt;/strong&gt;: Academic papers only, large installation (500MB-8GB), complex Java+Python setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: Apache-2.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to choose&lt;/strong&gt;: Scientific/academic document processing exclusively&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Commercial APIs
&lt;/h3&gt;

&lt;p&gt;There are numerous commercial options from startups (LlamaIndex, Unstructured.io paid tiers) to big cloud providers (AWS Textract, Azure Form Recognizer, Google Document AI). These are not OSS but offer managed infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kreuzberg's position&lt;/strong&gt;: As an open-source library, Kreuzberg provides a self-hosted alternative with no per-document API costs, making it suitable for high-volume workloads where cost efficiency matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community &amp;amp; Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: Star us at &lt;a href="https://github.com/kreuzberg-dev/kreuzberg" rel="noopener noreferrer"&gt;https://github.com/kreuzberg-dev/kreuzberg&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discord&lt;/strong&gt;: Join our community server at &lt;a href="https://discord.gg/pXxagNK2zN" rel="noopener noreferrer"&gt;discord.gg/pXxagNK2zN&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subreddit&lt;/strong&gt;: Join the discussion at &lt;a href="https://www.reddit.com/r/kreuzberg_dev/" rel="noopener noreferrer"&gt;r/kreuzberg_dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href="https://kreuzberg.dev" rel="noopener noreferrer"&gt;kreuzberg.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'd love to hear your feedback, use cases, and contributions!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Kreuzberg v4 is a complete Rust rewrite of a document intelligence library, offering native bindings for 7 languages (8 runtime targets), 56+ file formats, Rust-native performance, embeddings, semantic chunking, and production-ready servers - all in a 16-31 MB complete package (5-15x smaller than alternatives). Releasing January 2026. MIT licensed forever.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>programming</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I benchmarked 4 Python text extraction libraries (2025)</title>
      <dc:creator>Na'aman Hirschfeld (Goldziher)</dc:creator>
      <pubDate>Sun, 06 Jul 2025 10:25:38 +0000</pubDate>
      <link>https://forem.com/nhirschfeld/i-benchmarked-4-python-text-extraction-libraries-2025-4e7j</link>
      <guid>https://forem.com/nhirschfeld/i-benchmarked-4-python-text-extraction-libraries-2025-4e7j</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Comprehensive benchmarks of Kreuzberg, Docling, MarkItDown, and Unstructured across 94 real-world documents. Results might surprise you.&lt;/p&gt;

&lt;h2&gt;
  
  
  📊 &lt;strong&gt;Live Results&lt;/strong&gt;: &lt;a href="https://goldziher.github.io/python-text-extraction-libs-benchmarks/" rel="noopener noreferrer"&gt;https://goldziher.github.io/python-text-extraction-libs-benchmarks/&lt;/a&gt;
&lt;/h2&gt;




&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;As the author of &lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;Kreuzberg&lt;/a&gt;, I wanted to create an &lt;strong&gt;honest, comprehensive benchmark&lt;/strong&gt; of Python text extraction libraries. No cherry-picking, no marketing fluff - just real performance data across 94 documents (~210MB) ranging from tiny text files to 59MB academic papers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full disclosure&lt;/strong&gt;: I built Kreuzberg, but these benchmarks are automated, reproducible, and the methodology is completely open-source.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔬 &lt;strong&gt;What I Tested&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Libraries Benchmarked:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;Kreuzberg&lt;/a&gt;&lt;/strong&gt; (71MB, 20 deps) - My library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/DS4SD/docling" rel="noopener noreferrer"&gt;Docling&lt;/a&gt;&lt;/strong&gt; (1,032MB, 88 deps) - IBM's ML-powered solution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/microsoft/markitdown" rel="noopener noreferrer"&gt;MarkItDown&lt;/a&gt;&lt;/strong&gt; (251MB, 25 deps) - Microsoft's Markdown converter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/Unstructured-IO/unstructured" rel="noopener noreferrer"&gt;Unstructured&lt;/a&gt;&lt;/strong&gt; (146MB, 54 deps) - Enterprise document processing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test Coverage:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;94 real documents&lt;/strong&gt;: PDFs, Word docs, HTML, images, spreadsheets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 size categories&lt;/strong&gt;: Tiny (&amp;lt;100KB) to Huge (&amp;gt;50MB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 languages&lt;/strong&gt;: English, Hebrew, German, Chinese, Japanese, Korean&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU-only processing&lt;/strong&gt;: No GPU acceleration for fair comparison&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple metrics&lt;/strong&gt;: Speed, memory usage, success rates, installation sizes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏆 &lt;strong&gt;Results Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Speed Champions 🚀
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Kreuzberg&lt;/strong&gt;: 35+ files/second, handles everything&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured&lt;/strong&gt;: Moderate speed, excellent reliability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MarkItDown&lt;/strong&gt;: Good on simple docs, struggles with complex files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docling&lt;/strong&gt;: Often 60+ minutes per file (!!)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Installation Footprint 📦
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kreuzberg&lt;/strong&gt;: 71MB, 20 dependencies ⚡&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured&lt;/strong&gt;: 146MB, 54 dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MarkItDown&lt;/strong&gt;: 251MB, 25 dependencies (includes ONNX)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docling&lt;/strong&gt;: 1,032MB, 88 dependencies 🐘&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reality Check ⚠️
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docling&lt;/strong&gt;: Frequently fails/times out on medium files (&amp;gt;1MB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MarkItDown&lt;/strong&gt;: Struggles with large/complex documents (&amp;gt;10MB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kreuzberg&lt;/strong&gt;: Consistent across all document types and sizes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured&lt;/strong&gt;: Most reliable overall (88%+ success rate)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 &lt;strong&gt;When to Use What&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⚡ &lt;strong&gt;&lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;Kreuzberg&lt;/a&gt;&lt;/strong&gt; (Disclaimer: I built this)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for&lt;/strong&gt;: Production workloads, edge computing, AWS Lambda&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why&lt;/strong&gt;: Smallest footprint (71MB), fastest speed, handles everything&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bonus&lt;/strong&gt;: Both sync/async APIs with OCR support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🏢 &lt;strong&gt;&lt;a href="https://github.com/Unstructured-IO/unstructured" rel="noopener noreferrer"&gt;Unstructured&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for&lt;/strong&gt;: Enterprise applications, mixed document types&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why&lt;/strong&gt;: Most reliable overall, good enterprise features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-off&lt;/strong&gt;: Moderate speed, larger installation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📝 &lt;strong&gt;&lt;a href="https://github.com/microsoft/markitdown" rel="noopener noreferrer"&gt;MarkItDown&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for&lt;/strong&gt;: Simple documents, LLM preprocessing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why&lt;/strong&gt;: Good for basic PDFs/Office docs, optimized for Markdown&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitation&lt;/strong&gt;: Fails on large/complex files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔬 &lt;strong&gt;&lt;a href="https://github.com/DS4SD/docling" rel="noopener noreferrer"&gt;Docling&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for&lt;/strong&gt;: Research environments (if you have patience)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why&lt;/strong&gt;: Advanced ML document understanding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reality&lt;/strong&gt;: Extremely slow, frequent timeouts, 1GB+ install&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📈 &lt;strong&gt;Key Insights&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Installation size matters&lt;/strong&gt;: Kreuzberg's 71MB vs Docling's 1GB+ makes a huge difference for deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance varies dramatically&lt;/strong&gt;: 35 files/second vs 60+ minutes per file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document complexity is crucial&lt;/strong&gt;: Simple PDFs vs complex layouts show very different results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability vs features&lt;/strong&gt;: Sometimes the simplest solution works best&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔧 &lt;strong&gt;Methodology&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated CI/CD&lt;/strong&gt;: GitHub Actions run benchmarks on every release&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real documents&lt;/strong&gt;: Academic papers, business docs, multilingual content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple iterations&lt;/strong&gt;: 3 runs per document, statistical analysis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source&lt;/strong&gt;: Full code, test documents, and results available&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory profiling&lt;/strong&gt;: psutil-based resource monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout handling&lt;/strong&gt;: 5-minute limit per extraction&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤔 &lt;strong&gt;Why I Built This&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Working on &lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;Kreuzberg&lt;/a&gt;, I worked on performance and stability, and then wanted a tool to see how it measures against other frameworks - which I could also use to further develop and improve Kreuzberg itself. I therefore created this benchmark. Since it was fun, I invested some time to pimp it out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;strong&gt;real-world documents&lt;/strong&gt;, not synthetic tests&lt;/li&gt;
&lt;li&gt;Tests &lt;strong&gt;installation overhead&lt;/strong&gt; (often ignored)&lt;/li&gt;
&lt;li&gt;Includes &lt;strong&gt;failure analysis&lt;/strong&gt; (libraries fail more than you think)&lt;/li&gt;
&lt;li&gt;Is &lt;strong&gt;completely reproducible&lt;/strong&gt; and open&lt;/li&gt;
&lt;li&gt;Updates &lt;strong&gt;automatically&lt;/strong&gt; with new releases&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📊 &lt;strong&gt;Data Deep Dive&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://goldziher.github.io/python-text-extraction-libs-benchmarks/" rel="noopener noreferrer"&gt;interactive dashboard&lt;/a&gt; shows some fascinating patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kreuzberg dominates&lt;/strong&gt; on speed and resource usage across all categories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured excels&lt;/strong&gt; at complex layouts and has the best reliability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MarkItDown is useful&lt;/strong&gt; for simple docs shows in the data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docling's ML models&lt;/strong&gt; create massive overhead for most use cases making it a hard sell&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 &lt;strong&gt;Try It Yourself&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Goldziher/python-text-extraction-libs-benchmarks.git
&lt;span class="nb"&gt;cd &lt;/span&gt;python-text-extraction-libs-benchmarks
uv &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--all-extras&lt;/span&gt;
uv run python &lt;span class="nt"&gt;-m&lt;/span&gt; src.cli benchmark &lt;span class="nt"&gt;--framework&lt;/span&gt; kreuzberg_sync &lt;span class="nt"&gt;--category&lt;/span&gt; small
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or just check the live results: &lt;a href="https://goldziher.github.io/python-text-extraction-libs-benchmarks/" rel="noopener noreferrer"&gt;https://goldziher.github.io/python-text-extraction-libs-benchmarks/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 &lt;strong&gt;Links&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;📊 Live Benchmark Results&lt;/strong&gt;: &lt;a href="https://goldziher.github.io/python-text-extraction-libs-benchmarks/" rel="noopener noreferrer"&gt;https://goldziher.github.io/python-text-extraction-libs-benchmarks/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📁 Benchmark Repository&lt;/strong&gt;: &lt;a href="https://github.com/Goldziher/python-text-extraction-libs-benchmarks" rel="noopener noreferrer"&gt;https://github.com/Goldziher/python-text-extraction-libs-benchmarks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Kreuzberg (my library)&lt;/strong&gt;: &lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;https://github.com/Goldziher/kreuzberg&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔬 Docling&lt;/strong&gt;: &lt;a href="https://github.com/DS4SD/docling" rel="noopener noreferrer"&gt;https://github.com/DS4SD/docling&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📝 MarkItDown&lt;/strong&gt;: &lt;a href="https://github.com/microsoft/markitdown" rel="noopener noreferrer"&gt;https://github.com/microsoft/markitdown&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🏢 Unstructured&lt;/strong&gt;: &lt;a href="https://github.com/Unstructured-IO/unstructured" rel="noopener noreferrer"&gt;https://github.com/Unstructured-IO/unstructured&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤝 &lt;strong&gt;Discussion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What's your experience with these libraries? Any others I should benchmark? I tried benchmarking &lt;code&gt;marker&lt;/code&gt;, but the setup required a GPU.&lt;/p&gt;

&lt;p&gt;Some important points regarding how I used these benchmarks for Kreuzberg:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I fine tuned the default settings for Kreuzberg.&lt;/li&gt;
&lt;li&gt;I updated our docs to give recommendations on different settings for different use cases. E.g. Kreuzberg can actually get to 75% reliability, with about 15% slow-down.&lt;/li&gt;
&lt;li&gt;I made a best effort to configure the frameworks following the best practices of their docs and using their out of the box defaults. If you think something is off or needs adjustment, feel free to let me know here or open an issue in the repository.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>ai</category>
    </item>
    <item>
      <title>Announcing Kreuzberg v2.0: A Lightweight, Modern Python Text Extraction library</title>
      <dc:creator>Na'aman Hirschfeld (Goldziher)</dc:creator>
      <pubDate>Sat, 15 Feb 2025 18:44:30 +0000</pubDate>
      <link>https://forem.com/nhirschfeld/announcing-kreuzberg-v20-a-lightweight-modern-python-text-extraction-library-4ca4</link>
      <guid>https://forem.com/nhirschfeld/announcing-kreuzberg-v20-a-lightweight-modern-python-text-extraction-library-4ca4</guid>
      <description>&lt;h2&gt;
  
  
  🔍 What’s Kreuzberg?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;Kreuzberg&lt;/a&gt; is a Python library that provides a unified async/sync interface for extracting text from PDFs, images, Office documents, and more. &lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async First&lt;/strong&gt;: Optimized async using &lt;code&gt;anyio&lt;/code&gt; and worker processes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Dependencies&lt;/strong&gt;: Much smaller footprint compared to alternatives.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless-and-Docker Ready&lt;/strong&gt;: Perfect for serverless functions and containerized deployments.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Processing&lt;/strong&gt;: All processing is done locally, with no API calls or cloud services.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern Python&lt;/strong&gt;: Built for Python 3.9+ with rigorous typing and extensive testing.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versatile&lt;/strong&gt;: Supports various formats, including PDFs, spreadsheets, Markdown, LaTeX, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 What’s New in Version 2.0?
&lt;/h2&gt;

&lt;p&gt;Kreuzberg v2.0 brings significant enhancements to performance, usability, and feature set. Here’s what’s new:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sync APIs&lt;/strong&gt;: Kreuzberg supports synchronous extraction methods alongside async workflows.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: Efficiently process multiple files or byte streams in parallel.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart PDF Handling&lt;/strong&gt;: Automatically fall back to OCR when direct text extraction fails.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Extraction&lt;/strong&gt;: Retrieve metadata like document titles or creators using Pandoc.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excel Multi-Sheet Support&lt;/strong&gt;: Handle even the most complex spreadsheets.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Performance&lt;/strong&gt;: Worker processes for faster, resource-efficient extraction.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/Goldziher/kreuzberg/releases/tag/v2.0.0" rel="noopener noreferrer"&gt;v2.0 changelog&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Who’s It For?
&lt;/h2&gt;

&lt;p&gt;Kreuzberg is ideal for developers building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval-Augmented Generation (RAG) systems&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM-powered applications&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document indexing, analysis, and automation tools&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re looking for a lightweight, efficient solution for text extraction, Kreuzberg is a great choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚖️ How Kreuzberg Compares
&lt;/h2&gt;

&lt;p&gt;Here’s how Kreuzberg stacks up against alternatives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python OSS Libraries&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured.io&lt;/strong&gt;: Feature-rich but heavy, making it unsuitable for serverless or low-resource environments.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docling&lt;/strong&gt;: Another strong alternative but larger and heavier—better suited for high-volume, GPU-based workloads.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Non-Python OSS Libraries&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Apache Tika&lt;/strong&gt;: Requires a Java server running as a sidecar, with Python client libraries available.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grobid&lt;/strong&gt;: Excellent for structured research text extraction but comes with a ~20GB Docker image.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Commercial APIs&lt;/strong&gt;&lt;br&gt;
Paid solutions like Azure Document Intelligence or AWS Textract offer best-in-class OCR and layout extraction. However, they come with pricing concerns and cloud dependencies, unlike Kreuzberg.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Staring ⭐ is Caring
&lt;/h2&gt;

&lt;p&gt;If Kreuzberg sounds like the library you’ve been looking for, check it out on &lt;a href="https://github.com/Goldziher/kreuzberg" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please star the repo ⭐—it helps others discover the project and motivates me to keep improving it!&lt;/p&gt;

</description>
      <category>llm</category>
      <category>rag</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Functional Snippet: withSuppress</title>
      <dc:creator>Na'aman Hirschfeld (Goldziher)</dc:creator>
      <pubDate>Sun, 01 Sep 2024 12:31:51 +0000</pubDate>
      <link>https://forem.com/nhirschfeld/functional-snippet-withsuppress-4ea0</link>
      <guid>https://forem.com/nhirschfeld/functional-snippet-withsuppress-4ea0</guid>
      <description>&lt;p&gt;Sometimes, suppressing errors is handy. &lt;/p&gt;

&lt;p&gt;E.g. you see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;scrollableRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's create something to handle this in a cleaner fashion. We'll use a functional style that prefers wrap functions to extend functionality. &lt;/p&gt;

&lt;p&gt;We "wrap" a function with error handling, returning a function with an identical signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isPromise&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tool-belt/type-predicates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Wraps a function with error suppression and optional logging.
 *
 * @param fn - The function to execute.
 * @param errorMessage - The error message to log if an exception is thrown.
 * @returns The wrapped function with error suppression.
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;extends &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we can suppress errors elegantly. &lt;/p&gt;

&lt;p&gt;Here are some example uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a Vitest test suite for the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withSuppress&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./functional&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;withSuppress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return the value from a synchronous function without errors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return undefined and log error when synchronous function throws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sync error occurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBeUndefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringContaining&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\nError: Test Error`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockRestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return the resolved value from an asynchronous function without errors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asyncFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;resolves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return undefined and log error when asynchronous function rejects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Async error occurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asyncFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;resolves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeUndefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringContaining&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\nError: Test Error`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockRestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return undefined if no error message is provided and the function throws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBeUndefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockRestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return undefined if no error message is provided and the async function rejects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asyncFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;resolves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeUndefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;consoleErrorSpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockRestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should handle functions that return promises without errors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asyncFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;resolves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should handle synchronous functions returning undefined without errors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrappedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withSuppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrappedFn&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toBeUndefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>functional</category>
      <category>util</category>
    </item>
    <item>
      <title>Starlite December '22 Updates</title>
      <dc:creator>Na'aman Hirschfeld (Goldziher)</dc:creator>
      <pubDate>Sun, 11 Dec 2022 13:31:27 +0000</pubDate>
      <link>https://forem.com/nhirschfeld/starlite-december-22-updates-52dc</link>
      <guid>https://forem.com/nhirschfeld/starlite-december-22-updates-52dc</guid>
      <description>&lt;h1&gt;
  
  
  Starlite December '22 Updates
&lt;/h1&gt;

&lt;p&gt;Hi Pythonistas!&lt;/p&gt;

&lt;p&gt;This post is an update on the development status of &lt;a href="https://github.com/starlite-api/starlite" rel="noopener noreferrer"&gt;Starlite&lt;/a&gt;. Let me start, as usual, with a short intro about what is &lt;a href="https://github.com/starlite-api/starlite" rel="noopener noreferrer"&gt;Starlite&lt;/a&gt; - for those of you unfamiliar with it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/starlite-api/starlite" rel="noopener noreferrer"&gt;Starlite&lt;/a&gt; is a Python ASGI API framework. ASGI is an async python API specification, originally from the good folk over at the Django project, and an ASGI API framework is a framework that follows this specification. You might be familiar with other ASGI frameworks, with the most famous one these days being FastAPI. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/starlite-api/starlite" rel="noopener noreferrer"&gt;Starlite&lt;/a&gt; began as an alternative to FastAPI - it was originally built on the same foundation- Starlette, which offers a ready to use ASGI "tool-kit". The name of the framework - Starlite, was meant to highlight this relationship. Yet, over time Starlite grew in sophistication and complextiy, and we made the decision to drop Starlette as a dependency because this no longer made any sense. &lt;/p&gt;

&lt;h2&gt;
  
  
  Dropping Starlette and Benchmarks
&lt;/h2&gt;

&lt;p&gt;Since version &lt;code&gt;v1.39.0&lt;/code&gt; Starlite (released on the 12.11.22) no longer has any dependency on Starlette. Between this version and &lt;code&gt;v1.45.0&lt;/code&gt; that was released today (11.12.22), we have invested significant effort into benchmarking and optimizing code. One of our maintainers, @provinzkraut (Janek Nouvertné), has done amazing work rewriting our benchmarking framework. You can read more about this in &lt;a href="https://starlite-api.github.io/starlite/benchmarks/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and run the benchmarks on your own by cloning &lt;a href="https://github.com/starlite-api/api-performance-tests" rel="noopener noreferrer"&gt;the benchmark repository&lt;/a&gt;. The results are pretty impressive if I may say so myself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flil7femi9ph9d1gw96y5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flil7femi9ph9d1gw96y5.png" alt="Response Cookies and Headers" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrxzx5kga9vwng4903i1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrxzx5kga9vwng4903i1.png" alt="File Download" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fup0r3smiashxlbgz1t96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fup0r3smiashxlbgz1t96.png" alt="JSON Response" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vkwv17fr0sirkhx7ik1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vkwv17fr0sirkhx7ik1.png" alt="Query and Path Parameters" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F109capw1z7f95w0071kv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F109capw1z7f95w0071kv.png" alt="Plaintext Response" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dkjsy8xvftfrw6xdfun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dkjsy8xvftfrw6xdfun.png" alt="URLEncoded and Multipart" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4az9ozzhp5sv635arx68.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4az9ozzhp5sv635arx68.png" alt="JSON Post Data" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5atv1md5y9nls2jhbdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5atv1md5y9nls2jhbdz.png" alt="Pydantic and Dataclass Serialization" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Important Changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Contrib and Security Backends
&lt;/h3&gt;

&lt;p&gt;Another important development is the inclusion of a &lt;code&gt;starlite.contrib&lt;/code&gt; namespace, which we will be expanding on in the future. &lt;/p&gt;

&lt;p&gt;This namespace includes an optional &lt;a href="https://starlite-api.github.io/starlite/usage/18-contrib/0-open-telemetry/" rel="noopener noreferrer"&gt;OpenTelemetry Integration&lt;/a&gt;, which was a long awaited feature.&lt;/p&gt;

&lt;p&gt;We also added &lt;a href="https://starlite-api.github.io/starlite/usage/8-security/0-intro/" rel="noopener noreferrer"&gt;Security Backend&lt;/a&gt; support, which was discussed in some length &lt;a href="https://github.com/starlite-api/starlite/discussions/794" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The new security backend supports all of the different &lt;a href="https://starlite-api.github.io/starlite/usage/8-security/2-security-backends/" rel="noopener noreferrer"&gt;session backends&lt;/a&gt; Starlite supports, and there is also an optional &lt;a href="https://starlite-api.github.io/starlite/usage/18-contrib/1-jwt/" rel="noopener noreferrer"&gt;JWT Security Backend&lt;/a&gt; as part of contrib.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yield Based Dependencies
&lt;/h3&gt;

&lt;p&gt;We made some updates to dependencies following a request on reddit - we now support yield based dependencies in the Starlite &lt;a href="https://starlite-api.github.io/starlite/usage/6-dependency-injection/0-dependency-injection-intro/" rel="noopener noreferrer"&gt;Dependency Injection&lt;/a&gt; framework. Additionally we made some optimizations to dependency injection which allows us to resolve dependencies in parallel and do some caching, the result is a significant boost in speed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpk3kq7r1i5pn8xvtabcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpk3kq7r1i5pn8xvtabcg.png" alt="Dependency Injection Performance" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Call for Contributiors and Maintainers
&lt;/h2&gt;

&lt;p&gt;The original imperative for creating &lt;a href="https://github.com/starlite-api/starlite" rel="noopener noreferrer"&gt;Starlite&lt;/a&gt; was to create a community driven alternative to FastAPI. This was and remains a core pillar of Starlite- to have multiple maintainers and be as open, inviting and accessible for contributions as feasible. The project follows the &lt;a href="https://allcontributors.org/docs/en/specification" rel="noopener noreferrer"&gt;all-contributors specification&lt;/a&gt; and we attribute all types of contribution - code, testing, refactoring, code reviews, documentation, design of the docs, writing and evangelizing etc.&lt;/p&gt;

&lt;p&gt;We are a growing group of contributors and maintainers (5 maintainers at present), and we are always looking for more people to be involved. You're invited to join us on our &lt;a href="https://discord.gg/X3FJqy8d2j" rel="noopener noreferrer"&gt;discord server&lt;/a&gt;, or checkout our &lt;a href="https://github.com/starlite-api/starlite" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; where you are welcome to write in both discussions and issues.&lt;/p&gt;

</description>
      <category>starlite</category>
      <category>webdev</category>
      <category>python</category>
      <category>api</category>
    </item>
  </channel>
</rss>
