{"id":13503109,"url":"https://github.com/greyblake/envconfig-rs","last_synced_at":"2025-04-12T16:35:40.457Z","repository":{"id":45755128,"uuid":"148540243","full_name":"greyblake/envconfig-rs","owner":"greyblake","description":"Build a config structure from environment variables in Rust without boilerplate","archived":false,"fork":false,"pushed_at":"2023-05-28T22:53:11.000Z","size":122,"stargazers_count":190,"open_issues_count":7,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-29T16:56:47.621Z","etag":null,"topics":["12-factor","configuration","environment","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greyblake.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-09-12T20:48:17.000Z","updated_at":"2024-05-16T06:31:06.000Z","dependencies_parsed_at":"2022-09-03T00:01:01.354Z","dependency_job_id":"4d0bb128-70fa-4292-bd6e-03f9385eea41","html_url":"https://github.com/greyblake/envconfig-rs","commit_stats":{"total_commits":92,"total_committers":8,"mean_commits":11.5,"dds":"0.17391304347826086","last_synced_commit":"e889dcc5d2236d0b66968269ec7abdeabe146627"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greyblake%2Fenvconfig-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greyblake%2Fenvconfig-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greyblake%2Fenvconfig-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greyblake%2Fenvconfig-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greyblake","download_url":"https://codeload.github.com/greyblake/envconfig-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248597185,"owners_count":21130829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["12-factor","configuration","environment","rust"],"created_at":"2024-07-31T22:02:37.412Z","updated_at":"2025-04-12T16:35:40.401Z","avatar_url":"https://github.com/greyblake.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"200\" src=\"https://raw.githubusercontent.com/greyblake/envconfig-rs/master/logo/envconfig.svg\" alt=\"Envconfig logo\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://travis-ci.org/greyblake/envconfig-rs\" rel=\"nofollow\"\u003e\u003cimg src=\"https://travis-ci.org/greyblake/envconfig-rs.svg?branch=master\" alt=\"Build Status\"\u003e\u003c/a\u003e\n\u003ca href=\"https://raw.githubusercontent.com/greyblake/envconfig-rs/master/LICENSE\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n\u003ca href=\"https://docs.rs/envconfig\" rel=\"nofollow\"\u003e\u003cimg src=\"https://docs.rs/envconfig/badge.svg\" alt=\"Documentation\"\u003e\u003c/a\u003e\n\u003cp\u003e\n\n\u003cp align=\"center\"\u003eInitialize config structure from environment variables in Rust without boilerplate.\u003c/p\u003e\n\n[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua/)\n\n## Install\n\n```rust\n[dependencies]\nenvconfig = \"0.10.0\"\n```\n\n## Usage\n\n### Basic example\n\nLet's say you application relies on the following environment variables:\n\n* `DB_HOST`\n* `DB_PORT`\n\nAnd you want to initialize `Config` structure like this one:\n\n```rust,ignore\nstruct Config {\n    db_host: String,\n    db_port: u16,\n}\n```\n\nYou can achieve this with the following code without boilerplate:\n\n```rust\nuse envconfig::Envconfig;\n\n#[derive(Envconfig)]\npub struct Config {\n    #[envconfig(from = \"DB_HOST\")]\n    pub db_host: String,\n\n    #[envconfig(from = \"DB_PORT\", default = \"5432\")]\n    pub db_port: u16,\n}\n\nfn main() {\n    // Assuming the following environment variables are set\n    std::env::set_var(\"DB_HOST\", \"127.0.0.1\");\n\n    // Initialize config from environment variables or terminate the process.\n    let config = Config::init_from_env().unwrap();\n\n    assert_eq!(config.db_host, \"127.0.0.1\");\n    assert_eq!(config.db_port, 5432);\n}\n```\n\n### Nested configs\n\nConfigs can be nested. Just add `#[envconfig(nested)]` to nested field.\n\n```rust\n#[derive(Envconfig)]\npub struct DbConfig {\n    #[envconfig(from = \"DB_HOST\")]\n    pub host: String,\n\n    #[envconfig(from = \"DB_PORT\", default = \"5432\")]\n    pub port: u16,\n}\n\n#[derive(Envconfig)]\npub struct Config {\n    #[envconfig(nested)]     // \u003c---\n    db: DbConfig,\n\n    #[envconfig(from = \"HOSTNAME\")]\n    hostname: String,\n}\n```\n\n\n### Custom types\n\nUnder the hood envconfig relies on [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) trait.\nIf you want to use a custom type as a field for config, you have to implement `FromStr` trait for your custom type.\n\nLet's say we want to extend `DbConfig` with `driver` field, which is `DbDriver` enum that represents either `Postgresql` or `Mysql`:\n\n```rust\npub enum DbDriver {\n    Postgresql,\n    Mysql,\n}\n\nimpl std::str::FromStr for DbDriver {\n    type Err = String;\n\n    fn from_str(s: \u0026str) -\u003e Result\u003cSelf, Self::Err\u003e {\n        match s.trim().to_lowercase().as_ref() {\n            \"postgres\" =\u003e Ok(DbDriver::Postgresql),\n            \"mysql\" =\u003e Ok(DbDriver::Mysql),\n            _ =\u003e Err(format!(\"Unknown DB driver: {s}\"))\n        }\n    }\n}\n\n#[derive(Envconfig)]\npub struct DbConfig {\n    // ...\n    #[envconfig(from = \"DB_DRIVER\")]\n    pub driver: DbDriver,\n}\n```\n\nIf this seems too cumbersome, consider using other crates like [strum](https://docs.rs/strum/latest/strum/) to derive `FromStr` automatically.\n\n```rust\nuse strum::EnumString;\n\n#[derive(EnumString)]\npub enum DbDriver {\n    Postgresql,\n    Mysql,\n}\n```\n\n## Testing\n\nWhen writing tests you should avoid using environment variables. Cargo runs Rust tests in parallel by default which means\nyou can end up with race conditions in your tests if two or more are fighting over an environment variable.\n\nTo solve this you can initialise your `struct` from a `HashMap\u003cString, String\u003e` in your tests. The `HashMap` should\nmatch what you expect the real environment variables to be; for example `DB_HOST` environment variable becomes a\n`DB_HOST` key in your `HashMap`.\n\n```rust\nuse envconfig::Envconfig;\n\n#[derive(Envconfig)]\npub struct Config {\n    #[envconfig(from = \"DB_HOST\")]\n    pub db_host: String,\n\n    #[envconfig(from = \"DB_PORT\", default = \"5432\")]\n    pub db_port: u16,\n}\n\n#[test]\nfn test_config_can_be_loaded_from_hashmap() {\n    // Create a HashMap that looks like your environment\n    let mut hashmap = HashMap::new();\n    hashmap.insert(\"DB_HOST\".to_string(), \"127.0.0.1\".to_string());\n\n    // Initialize config from a HashMap to avoid test race conditions\n    let config = Config::init_from_hashmap(\u0026hashmap).unwrap();\n\n    assert_eq!(config.db_host, \"127.0.0.1\");\n    assert_eq!(config.db_port, 5432);\n}\n```\n\n## Contributing\n\n### Running tests\n\nTests do some manipulation with environment variables, so to\nprevent flaky tests they have to be executed in a single thread:\n\n```\ncargo test -- --test-threads=1\n```\n\n## License\n\n[MIT](https://github.com/greyblake/envconfig-rs/blob/master/LICENSE) © [Sergey Potapov](http://greyblake.com/)\n\n## Contributors\n\n- [greyblake](https://github.com/greyblake) Potapov Sergey - creator, maintainer.\n- [allevo](https://github.com/allevo) Tommaso Allevi - support nested structures\n- [hobofan](https://github.com/hobofan) Maximilian Goisser - update dependencies\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreyblake%2Fenvconfig-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreyblake%2Fenvconfig-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreyblake%2Fenvconfig-rs/lists"}