A unified configuration library combining environment variables and CLI arguments with a clear priority chain. Works like a combination of clap and dotenvy, but uses .lenv files via lino-env.
lino-arguments provides a unified configuration system that automatically loads configuration from multiple sources with a clear priority chain:
- CLI arguments - Highest priority (manually entered options)
- Environment variables - Already set in the process
.lenvfile - Links Notation environment file.envfile - Standard dotenv file (for compatibility)- Default values - Fallback values
Add to your Cargo.toml:
[dependencies]
lino-arguments = "0.2"Replace use clap::Parser with use lino_arguments::Parser, add lino_arguments::init() before Args::parse() — everything else stays the same:
use lino_arguments::Parser;
#[derive(Parser, Debug)]
#[command(name = "my-app")]
struct Args {
#[arg(long, env = "PORT", default_value = "3000")]
port: u16,
#[arg(long, env = "API_KEY")]
api_key: Option<String>,
#[arg(long, env = "VERBOSE")]
verbose: bool,
}
fn main() {
lino_arguments::init(); // loads .lenv + .env into process env
let args = Args::parse(); // standard clap API — no changes needed
println!("Server starting on port {}", args.port);
}With a .lenv file:
PORT: 8080
API_KEY: my-secret-key
Or a .env file:
PORT=8080
API_KEY=my-secret-key
The priority chain ensures CLI arguments always win:
# Uses default (3000)
cargo run
# Uses .lenv value (8080)
# (if PORT: 8080 is in .lenv)
cargo run
# Uses env var (9090)
PORT=9090 cargo run
# Uses CLI argument (7070)
cargo run -- --port 7070| Function | Description |
|---|---|
init() |
Load .lenv + .env files into process env |
init_with(lenv, env) |
Load specified files into process env |
For a single-call approach, use the LinoParser trait:
use lino_arguments::{Parser, LinoParser};
#[derive(Parser, Debug)]
struct Args {
#[arg(long, env = "PORT", default_value = "3000")]
port: u16,
}
fn main() {
let args = Args::lino_parse(); // loads .lenv + .env + parse in one call
}| Method | Description |
|---|---|
lino_parse() |
Load .lenv + .env, then parse CLI args |
lino_parse_with(lenv, env) |
Load specified files, then parse |
lino_parse_from(args) |
Load .lenv + .env, parse custom args (for testing) |
lino_parse_from_with(args, lenv, env) |
Load specified files, parse custom args |
For quick scripts or when you prefer not to define structs, use the functional builder API:
use lino_arguments::make_config_from;
fn main() {
let config = make_config_from(std::env::args_os(), |c| {
c.name("my-server")
.lenv(".lenv")
.env(".env")
.option_short("port", 'p', "Server port", "3000")
.option_short("api-key", 'k', "API key", "")
.flag_short("verbose", 'v', "Enable verbose logging")
});
let port = config.get_int("port", 3000);
let api_key = config.get("api-key");
let verbose = config.get_bool("verbose");
println!("Server starting on port {}", port);
}Parser- Derive macro and trait for struct-based CLI parsingArgs- Derive macro for argument groupsSubcommand- Derive macro for subcommandsValueEnum- Derive macro for enum value argumentsarg!- Macro for inline argument definitionscommand!- Macro for command metadata
| Function | Description |
|---|---|
init() |
Load .lenv + .env files from current directory |
init_with(lenv_path, env_path) |
Load specified .lenv and .env files |
| Function | Description |
|---|---|
load_lenv_file(path) |
Load .lenv file (won't overwrite existing env vars) |
load_lenv_file_override(path) |
Load .lenv file (overwrites existing env vars) |
load_env_file(path) |
Load .env file (won't overwrite existing env vars) |
load_env_file_override(path) |
Load .env file (overwrites existing env vars) |
Create configuration from CLI arguments and environment:
use lino_arguments::make_config;
let config = make_config(|c| {
c.lenv(".lenv")
.env(".env")
.option("port", "Server port", "3000")
.flag("verbose", "Enable verbose logging")
});Same as make_config but accepts custom arguments (useful for testing):
use lino_arguments::make_config_from;
let config = make_config_from(["app", "--port", "9090"], |c| {
c.option("port", "Server port", "3000")
});
assert_eq!(config.get("port"), "9090");| Method | Description |
|---|---|
.name(name) |
Set application name |
.about(description) |
Set application description |
.version(version) |
Set application version |
.lenv(path) |
Load .lenv file (without overriding existing env vars) |
.lenv_override(path) |
Load .lenv file (overriding existing env vars) |
.env(path) |
Load .env file (without overriding existing env vars) |
.env_override(path) |
Load .env file (overriding existing env vars) |
.option(name, desc, default) |
Define a string option |
.option_short(name, short, desc, default) |
Define a string option with short flag |
.flag(name, desc) |
Define a boolean flag |
.flag_short(name, short, desc) |
Define a boolean flag with short flag |
| Method | Description |
|---|---|
.get(key) |
Get value as string |
.get_int(key, default) |
Get value as integer |
.get_bool(key) |
Get value as boolean |
.has(key) |
Check if key exists |
Get environment variable as string with case-insensitive lookup.
let api_key = getenv("apiKey", "default-key"); // Tries API_KEY, apiKey, etc.Get environment variable as integer.
let port = getenv_int("PORT", 3000);Get environment variable as boolean. Accepts: "true", "false", "1", "0", "yes", "no".
let debug = getenv_bool("DEBUG", false);to_upper_case(s)- Convert to UPPER_CASEto_camel_case(s)- Convert to camelCaseto_kebab_case(s)- Convert to kebab-caseto_snake_case(s)- Convert to snake_caseto_pascal_case(s)- Convert to PascalCase
use lino_arguments::{to_upper_case, to_camel_case, to_kebab_case};
assert_eq!(to_upper_case("apiKey"), "API_KEY");
assert_eq!(to_camel_case("api-key"), "apiKey");
assert_eq!(to_kebab_case("apiKey"), "api-key");# Run struct-based example
cargo run --example struct_based -- --port 9090 --verbose
# Run functional example
cargo run --example functional -- --port 9090 --verbose
# Use environment variables
PORT=8080 cargo run --example struct_based# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run specific test
cargo test make_config# Build
cargo build
# Build release
cargo build --release
# Run clippy
cargo clippy
# Format code
cargo fmtThis is free and unencumbered software released into the public domain. See the LICENSE file for details.