rust
46 lines · 7 steps
Loading typed config from environment variables in Rust
A Config struct is populated from env vars with typed parsing, defaults, and clear errors.
Explained by
highlit
1use std::env;
2use std::time::Duration;
3
4#[derive(Debug, Clone)]
5pub struct Config {
6 pub host: String,
7 pub port: u16,
8 pub database_url: String,
9 pub max_connections: u32,
10 pub request_timeout: Duration,
11 pub debug: bool,
12}
13
14impl Config {
15 pub fn from_env() -> Result<Self, String> {
16 Ok(Config {
17 host: env::var("HOST").unwrap_or_else(|_| "127.0.0.1".into()),
18 port: parse_var("PORT", 8080)?,
19 database_url: env::var("DATABASE_URL")
20 .map_err(|_| "DATABASE_URL must be set".to_string())?,
21 max_connections: parse_var("MAX_CONNECTIONS", 16)?,
22 request_timeout: Duration::from_secs(parse_var("REQUEST_TIMEOUT_SECS", 30)?),
23 debug: parse_bool("DEBUG", false),
24 })
25 }
26}
27
28fn parse_var<T>(key: &str, default: T) -> Result<T, String>
29where
30 T: std::str::FromStr,
31{
32 match env::var(key) {
33 Ok(raw) => raw
34 .trim()
35 .parse()
36 .map_err(|_| format!("invalid value for {key}: {raw:?}")),
37 Err(_) => Ok(default),
38 }
39}
40
41fn parse_bool(key: &str, default: bool) -> bool {
42 match env::var(key) {
43 Ok(raw) => matches!(raw.trim().to_ascii_lowercase().as_str(), "1" | "true" | "yes" | "on"),
44 Err(_) => default,
45 }
46}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Centralizing config in one struct with a single loader keeps environment access out of the rest of the codebase.
- 2A generic helper over FromStr lets one function parse any target type while supplying defaults and consistent errors.
- 3Returning Result with descriptive messages surfaces misconfiguration at startup instead of failing mysteriously later.
Related explainers
rust
use axum::{ body::{Body, Bytes}, extract::Request, http::StatusCode,
Logging request and response sizes in Axum
middleware
http
streaming-bodies
Advanced
8 steps
rust
use std::borrow::Cow; pub fn escape_html(input: &str) -> Cow<'_, str> { let needs_escape = input
Zero-copy HTML escaping with Cow in Rust
clone-on-write
zero-copy
string-escaping
Intermediate
6 steps
rust
use once_cell::sync::Lazy; use regex::Regex; static CREDIT_CARD: Lazy<Regex> = Lazy::new(|| {
Redacting sensitive data from logs in Rust
regex
lazy-initialization
checksum-validation
Intermediate
9 steps
php
<?php namespace App\FeatureFlags;
How a feature flag evaluator decides
feature-flags
rollout
hashing
Intermediate
8 steps
go
type CreateUserInput struct { Name string `json:"name" binding:"required,min=2,max=64"` Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=8"`
Turning Gin validation errors into JSON
validation
request-binding
error-handling
Intermediate
9 steps
javascript
const express = require('express'); const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware'); const router = express.Router();
Building an API gateway proxy in Express
reverse-proxy
middleware
api-gateway
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/loading-typed-config-from-environment-variables-in-rust-explained-rust-0682/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.