NOML (Nested Object Markup Language) is a blazing-fast dynamic configuration language that revolutionizes how you handle configuration files. With industry-leading format preservation, zero-copy architecture, and 25ยตs parsing performance, NOML delivers both speed and power.
Unlike static markup languages, NOML is a markup/scripting hybrid that combines the simplicity of TOML with dynamic capabilities that traditional config formats simply cannot match.
๐ Performance That Matters
- โก 25ยตs parsing - Legitimately high-performance by industry standards
- โก 37ns reads - Blazing-fast value access with path-based navigation
- โก Zero-copy architecture - Optimized for real-world performance
- โก 47% faster - Massive optimization improvements over previous versions
๐ฏ Revolutionary Features
๐ฅ Format Preservation
Industry-first complete format preservation - maintain exact whitespace, comments, indentation, and styling during parsing and round-trip editing. Perfect for configuration management tools and IDEs.
๐ Dynamic Configuration
- Environment Variables:
env("DATABASE_URL", "default")
- String Interpolation:
"Welcome ${user.name}!"
- File Inclusion:
include "database.noml"
- Native Types:
@duration("30s")
,@size("10MB")
,@url("https://api.com")
๐ TOML Compatibility
Parse most TOML files with full format preservation - get advanced features while maintaining compatibility with existing TOML configurations.
๐ช Key Advantages
NOML vs Static Config Languages:
- 146% more features than TOML for only 2x performance cost
- Path-based access -
config.get("server.database.port")
vs manual navigation - Type system - Native parsing of sizes, durations, URLs, IPs
- Dynamic resolution - Runtime environment integration
- Format preservation - Perfect for editing tools and automation
๐ Quick Start
Add NOML to your Cargo.toml
:
[]
= "0.9"
Basic Usage
use parse;
let config = parse?;
// Fast path-based access
let app_name = config.get?.as_string?;
let port = config.get?.as_integer?;
let timeout = config.get?.as_duration?;
Format Preservation
use ;
// Parse with complete format preservation
let mut doc = parse_preserving_from_file?;
// Modify values while preserving formatting
doc = modify_preserving?;
// Save with perfect format fidelity
save_preserving?;
Advanced Configuration Management
use Config;
let mut config = from_file?;
// Merge multiple configs
config.merge_from_file?;
// Type-safe access with defaults
let port: u16 = config.get_or?;
let debug: bool = config.get_or?;
// Dynamic updates
config.set?;
config.save_to_file?;
๐ NOML Syntax
Environment Variables & Native Types
# Environment integration
database_url = env("DATABASE_URL", "sqlite:memory:")
api_key = env("API_KEY") # Required - will error if missing
# Native type parsing
max_file_size = @size("100MB") # Bytes: 104857600
cache_timeout = @duration("1h30m") # Seconds: 5400
api_endpoint = @url("https://api.example.com/v1")
server_ip = @ip("192.168.1.100")
String Interpolation & File Includes
app_name = "my-service"
log_file = "/var/log/${app_name}.log"
# Include other configuration files
database = include "database.noml"
secrets = include "secrets.noml"
Advanced Nesting & Arrays
[server.ssl]
enabled = true
cert_file = "/etc/ssl/cert.pem"
key_file = "/etc/ssl/private.key"
[[workers]]
name = "background-processor"
threads = 4
memory_limit = @size("512MB")
[[workers]]
name = "api-handler"
threads = 8
memory_limit = @size("1GB")
## ๐ **Performance Comparison**
NOML delivers **high-performance parsing** while providing **146% more features** than static alternatives:
| Parser | Parse Time | Features | Format Preservation |
|--------|------------|----------|-------------------|
| **NOML** | **25ยตs** | **32** | **โ
Complete** |
| TOML | 16ยตs | 13 | โ None |
| JSON | 10ยตs | 8 | โ None |
| YAML | 125ยตs | 15 | โ None |
**Real-world usage** (parse once + 10,000 reads): **NOML is only 1.95x slower than TOML** while delivering exponentially more functionality.
## ๐ **Command-Line Interface**
Install and use the NOML CLI:
```bash
cargo install noml
# Validate configuration files
noml validate config.noml
# Parse and display structure
noml parse app.noml
# Check version
noml version
๐ง Features & Compatibility
Cargo Features
[]
= { = "0.9", = ["chrono", "async"] }
chrono
- DateTime support with timezone handlingasync
- Async file operations and HTTP includes
TOML Compatibility
NOML can parse most TOML files with full format preservation:
// Parse TOML files with NOML for advanced features
let config = parse_from_file?;
let port = config.get?.as_integer?; // Path-based access
Note: ISO date formats (1979-05-27T15:32:00-08:00
) are not supported
๐ฏ Why Choose NOML?
For Configuration Management:
- Format Preservation - Perfect for automated configuration tools
- Environment Integration - Runtime environment variable resolution
- Type Safety - Native parsing eliminates custom conversion code
- Path Access - Clean dot-notation navigation
For Performance:
- 25ยตs parsing - Legitimately fast by industry standards
- 37ns reads - Blazing-fast value access
- Zero-copy architecture - Optimized for real-world usage
- Production ready - 124 comprehensive tests
For Developer Experience:
- Rich error messages - Precise source locations and helpful context
- Complete API - Covers all real-world configuration use cases
- TOML compatibility - Drop-in replacement for many TOML files
- Async support - Modern Rust patterns with tokio integration
Examples
Here are some examples of how to use the noml
library in your Rust code.
Basic Parsing
You can easily parse a NOML string and access its values.
## ๐ **Documentation & Resources**
- **
HTTP Includes Features:
- โ Secure HTTPS Support: Full support for HTTPS URLs with proper certificate validation
- โก Automatic Caching: Remote configs are cached to improve performance and reduce network requests
- ๐ Timeout Protection: Configurable request timeouts prevent hanging operations
- ๐ Error Handling: Clear error messages for network issues, HTTP errors, and parse failures
- ๐ฆ No Nested HTTP: HTTP includes cannot contain other HTTP includes (prevents security issues)
[]
= { = "0.9.0", = ["async"] }
= { = "1.0", = ["full"] }
Working with Native Types
noml
supports special native types for common configuration values like file sizes, durations, IP addresses, and more.
use parse;
let source = r#"
# File sizes and durations
max_upload_size = @size("256MB")
request_timeout = @duration("90s")
# Network and web
website = @url("https://example.com")
server_ip = @ip("192.168.1.100")
# Data formats
app_version = @semver("2.1.0")
secret_data = @base64("SGVsbG8gV29ybGQ=")
user_id = @uuid("550e8400-e29b-41d4-a716-446655440000")
"#;
let config = parse?;
// The values are parsed and validated
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Available Native Types:
@size("10MB")
- File/memory sizes (KB, MB, GB, etc.)@duration("30s")
- Time durations (s, m, h, d)@url("https://...")
- URL validation@ip("192.168.1.1")
- IP address validation (IPv4/IPv6)@semver("1.2.3")
- Semantic version parsing@base64("SGVsbG8=")
- Base64 encoded data@uuid("550e8400-...")
- UUID format validation
Working with Arrays and Tables
noml
fully supports arrays, inline tables, and arrays of tables, similar to TOML.
use parse;
let source = r#"
# An array of strings
allowed_roles = ["admin", "editor", "viewer"]
# An inline table
point = { x = 1.0, y = -1.0 }
# An array of tables
[[users]]
name = "Alice"
email = "alice@example.com"
[[users]]
name = "Bob"
email = "bob@example.com"
"#;
let config = parse?;
// Access array elements
let roles = config.get.unwrap.as_array?;
assert_eq!;
assert_eq!;
// Access inline table values
assert_eq!;
// Access values from an array of tables
let users = config.get.unwrap.as_array?;
assert_eq!;
assert_eq!;
High-Level Configuration Management
For more advanced use cases, the Config
struct provides a high-level API for loading, modifying, and saving configurations.
use Config;
use fs;
// Create a temporary file for the example
let temp_dir = tempdir?;
let file_path = temp_dir.path.join;
write?;
// Load the configuration from a file
let mut config = from_file?;
assert_eq!;
// Modify the configuration
config.set?;
config.set?;
// Save the changes back to the file
config.save?;
// Verify the changes
let updated_config = from_file?;
assert_eq!;
assert_eq!;
Async Support ๐
noml
supports async operations for modern Rust applications! Enable the async
feature:
[]
= { = "0.9.0", = ["async"] }
= { = "1.0", = ["full"] }
All parsing and file operations are available in async variants:
use ;
async
Thread Safety: All NOML types (Value
, Config
) are Send + Sync
, making them safe to share between async tasks and threads. Perfect for concurrent applications and microservices!
Performance: Async operations are non-blocking and integrate seamlessly with tokio
, async-std
, and other async runtimes.
Run the async demo: cargo run --example async_demo --features async
Schema Validation โ
noml
includes built-in schema validation to catch configuration errors early:
use ;
// Load your configuration
let config = from_string?;
// Define expected schema
let schema = new
.require_string
.require_integer
.optional_bool
.build;
// Validate configuration against schema
config.validate_schema?;
// Or create more complex schemas
let db_schema = new
.required_field
.required_field
.allow_additional;
let app_schema = new
.required_field
.required_field
.required_field;
config.validate_schema?;
Benefits:
- ๐ก๏ธ Early Error Detection: Catch configuration issues before runtime
- ๐ฏ Type Safety: Ensure values are the expected types
- ๐ Required Fields: Validate that critical configuration is present
- ๐ Clear Error Messages: Detailed validation failure reports