korni
An ultra-fast, nearly stateless, and failure-tolerant parser for .env files, written in Rust.
Designed for high-performance tooling (LSPs, linters, formatters) and applications that need deep introspection into environment configuration files.
Features
- 🚀 Blazingly Fast: Heavily optimized using nearly zero-copy parsing (
Cowstrings) and SIMD-friendly slice iterators. - 📍 Introspective: Tracks exact line and column positions (spans) for keys, values, and comments.
- 💬 Comment Support: First-class support for parsing and preserving comments, including commented-out key-value pairs.
- 🛡️ Failure Tolerant: Continues parsing after errors, collecting all issues instead of halting on the first one.
- 📦 Zero Runtime Dependencies: Lightweight and easy to drop into any project.
Installation
[]
= "0.1.3"
Quick Start
use ;
API Reference
Core Types
Entry<'a>
The main parsing result type representing a single line in an .env file:
KeyValuePair<'a>
Represents a parsed key-value pair with full introspection:
ParseOptions
Configure parsing behavior:
// Presets
fast // Default: no comments, no positions
full // Comments + positions enabled
Position and Span
For precise location tracking:
QuoteType
Indicates how a value was quoted:
Parsing Functions
parse(input: &str) -> Vec<Entry>
Fast parsing - returns key-value pairs only, no position tracking:
let entries = parse;
parse_with_options(input: &str, options: ParseOptions) -> Vec<Entry>
Configurable parsing with custom options:
let entries = parse_with_options;
Builder API
The builder API provides a fluent interface for parsing from various sources:
From String
use Korni;
let env = from_str
.preserve_comments
.track_positions
.parse?;
println!;
From File
let env = from_file
.preserve_comments
.parse?;
Auto-discover File
Searches current directory and ancestors for the file:
let env = find_file?
.parse?;
From Bytes
let bytes = b"KEY=value";
let env = from_bytes.parse?;
From Reader
use Cursor;
let reader = new;
let env = from_reader.parse?;
Environment API
The Environment struct provides a HashMap-like interface:
use Korni;
let env = from_str.parse?;
// Get a value
let host = env.get; // Option<&str>
let port = env.get_or; // &str with default
// Get full entry with metadata
if let Some = env.get_entry
// Iterate all pairs
for pair in env.iter
// Check for errors
if env.has_errors
// Export to HashMap<String, String>
let map = env.to_map;
Iterator API
Stream entries one at a time for memory efficiency:
use ;
let parser = new;
let iter = new;
for entry in iter
Error Types
All parsing errors include byte offsets for precise error reporting:
// Get the byte offset of any error
let offset = error.offset;
Parsing Rules
Keys
- Must contain only ASCII alphanumeric characters and underscores (
[A-Za-z0-9_]) - Must NOT start with a digit
- No whitespace allowed between key and
=
VALID_KEY=value
_also_valid=value
# Invalid: 123_KEY=value (starts with digit)
# Invalid: KEY = value (whitespace around =)
Values
Unquoted Values
- Terminate at first whitespace or end of line
- Support line continuation with trailing backslash
KEY=simple_value
MULTI=line1\
line2
Single-Quoted Values
- Literal strings - no escape processing
- Must be closed on the same line
KEY='raw value with $VAR not expanded'
Double-Quoted Values
- Support escape sequences:
\n,\r,\t,\\,\",\$ - Unknown escapes are preserved literally
KEY="line1\nline2"
ESCAPED="contains \"quotes\""
Comments
- Lines starting with
#are comments - Inline comments:
KEY=value # comment(requires whitespace before#) - Commented-out pairs (
# KEY=value) are parsed withis_comment: true
Export Keyword
The optional export prefix is supported:
export DATABASE_URL=postgres://localhost/db
BOM Handling
- UTF-8 BOM (
\xEF\xBB\xBF) at file start is silently skipped - BOM in middle of file produces an error
Comparison with dotenvy
dotenvy is the standard, battle-tested crate for loading environment variables in Rust applications. korni serves a different, more specialized purpose.
| Feature | dotenvy |
korni |
|---|---|---|
| Primary Goal | Load env vars into std::env |
Parse env files into structured data |
| Output | Modifies process environment | AST / Structured Iterators |
| Introspection | None (opaque loading) | Full (Spans, Line/Col, Offsets) |
| Comments | Ignored | Parsed & Preserved |
| Error Handling | Stops on first error | Failure-tolerant (collects all errors) |
Modifies std::env |
✅ Yes | ❌ No (Pure parsing) |
| Use Case | Application Configuration | Tooling (IDEs, Linters), Complex Configs |
When to use dotenvy
- You just want
cargo runto pick up your.envfile. - You need standard, 12-factor app configuration.
When to use korni
- You are building an IDE plugin, linter, or formatter.
- You need to analyze the structure of an
.envfile (e.g. "where isDB_PORTdefined?"). - You need performance-critical parsing of massive files.
- You want to manually control how environment variables are applied.
Specification & Compliance
EDF Specification
This parser implements the EDF (Ecolog Dotenv File Format) 1.0.0 specification.
Compliance Statement
korni aims for EDF 1.0.0 compliance. Per the specification's compliance requirements:
A parser implementation claiming EDF 1.0.0 Compliance MUST adhere to ALL requirements specified in the specification. This is a strict, all-or-nothing compliance model.
Requirements Implemented
- ✅ Parsing Rules: Keys, values (quoted/unquoted), comments, and multiline handling per Section 4
- ✅ Error Handling: Failure-tolerant parsing with detailed error messages including byte offsets
- ✅ Security: UTF-8 validation, BOM handling, error message safety
- ✅ Edge Cases: Empty values, escape sequences, line continuations
Allowed Variations (per spec)
This implementation varies in:
- Performance: Heavily optimized with focus on zero-copy parsing (but it is not absolutely zero-copy) and SIMD-friendly iterators
- API Design: Rust-idiomatic with
Cowstrings, builders, and iterators - Additional Features: Position tracking, comment parsing, and
is_commentflag for commented-out pairs
Version Compatibility
- Specification Version: EDF 1.0.0
- Semantic Versioning: This library follows semver. Major version bumps indicate potential parsing behavior changes.
License
MIT