smol_str

A small-string-optimized, immutable Rust string type with O(1) clone and no heap allocation for short strings.

Library
Cargo
v0.3.6
16,806stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
93/100Excellent
Development Activity100
Maintenance96
Community76
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture80
Code Quality82
Innovation78
Learning Curve80

smol_str is a compact, immutable string type for Rust built for situations where cheap cloning matters more than in-place mutability. It stores strings up to 23 bytes entirely on the stack, matching size_of::<String>() at 24 bytes, and falls back to a heap-allocated, reference-counted Arc<str> for longer content so that clones are O(1) instead of a fresh allocation and copy. It also special-cases whitespace-heavy strings — runs of newlines followed by spaces — so indentation-heavy source text stays inline even past the normal 23-byte threshold.

The crate originated inside rust-analyzer as the token and identifier storage type for a language server that clones the same short strings constantly while walking syntax trees, and it now ships as an independently versioned crate published from the rust-analyzer Cargo workspace. It is no_std-compatible (via alloc) and offers optional serde, borsh, and arbitrary integrations behind Cargo feature flags.

What You Get

  • A SmolStr type with O(1) Clone via inline storage or Arc<str> sharing, sized identically to std::String
  • SmolStrBuilder for incrementally constructing a SmolStr via push/push_str without intermediate String allocations
  • ToSmolStr and StrExt extension traits for ergonomic conversions and allocation-avoiding case-conversion/replace helpers
  • Optional serde and borsh (de)serialization support plus an arbitrary integration for fuzzing, all gated behind Cargo features
  • A #![no_std]-compatible build (with alloc) for use outside std environments

Common Use Cases

  • Interning tokens and identifiers in a compiler, parser, or language server where the same short strings are cloned repeatedly while walking a syntax tree
  • Storing string keys in large in-memory data structures where per-clone heap allocation would dominate runtime
  • Representing string literals and constant text from source code without allocating
  • Passing string data across API boundaries where cheap, shared ownership beats String’s exclusive-ownership clone cost

Under The Hood

Architecture SmolStr wraps a private Repr enum with three variants — Inline (a fixed byte buffer with a packed length tag), Static (a &'static str reference), and Heap (an Arc<str> for cheap shared cloning) — and every public operation dispatches through Repr’s own methods. The public surface (SmolStr, SmolStrBuilder, ToSmolStr, StrExt) lives in a single flat src/lib.rs, with serde.rs and borsh.rs split out behind feature gates. Because Display, Deref<Target=str>, equality, hashing, and the builder all funnel through Repr::as_str()/Repr::new(), the core enum is the crate’s single point of failure — the test suite explicitly locks size_of::<SmolStr>() to size_of::<String>(), so any change to the inline byte-packing scheme or the 23-byte threshold risks breaking that invariant silently.

Tech Stack Pure Rust, no_std-compatible via the alloc crate, with a minimal dependency surface: serde_core, borsh, and arbitrary are all optional and feature-gated, while dev-dependencies (proptest, serde_json, serde, criterion, rand) are used only for tests and benchmarks. The crate is a member of rust-analyzer’s Cargo workspace (lib/*) but is versioned and published to crates.io independently of the rust-analyzer binary itself, targeting a rolling MSRV pinned to the latest stable toolchain.

Code Quality A dedicated test suite covers conversions, size invariants, and builder behavior, including property-based tests via proptest for construction and equality; a separate tidy.rs test enforces repository formatting hygiene. The implementation leans heavily on unsafe for the inline byte-buffer transmutation and length packing, but each use carries an explicit // SAFETY: comment documenting the invariant it relies on. Criterion benchmarks track the crate’s hot paths — clone, case conversion, and replace — guarding against performance regressions, and the crate is exercised as part of rust-analyzer’s workspace-level CI.

API Design The public API keeps construction paths explicit rather than hiding them behind one polymorphic constructor: new, new_inline, and new_static each make a different cost/behavior trade-off clear at the call site. SmolStrBuilder mirrors String’s familiar push/push_str shape, and the ToSmolStr/StrExt extension traits let existing &str-oriented code opt into allocation-avoiding case conversion and replace operations without new free functions. Broad From/Deref<Target=str> coverage means SmolStr mostly drops into existing string-based APIs with little friction; the main developer cost is accepting immutability and routing in-place edits through SmolStrBuilder instead.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search