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 serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(untagged)]
Parsing flexible JSON shapes with serde
deserialization
enums
json
Intermediate
6 steps
ruby
require "shellwords" require "open3" module Backup
Building safe shell commands in Ruby
shell-out
subprocess
command-injection
Intermediate
7 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
rust
use std::cmp::{Ordering, Reverse}; use std::collections::BinaryHeap; use std::fs::File; use std::io::{self, BufRead, BufReader, BufWriter, Lines, Write};
K-way merge of sorted logs in Rust
binary-heap
k-way-merge
streaming-io
Intermediate
8 steps
rust
use axum::{ extract::{Path, State}, response::sse::{Event, KeepAlive, Sse}, };
Streaming import progress with SSE in Axum
server-sent-events
streams
watch-channel
Advanced
7 steps
rust
use std::f64::consts::PI; #[derive(Debug, Clone, Copy)] pub struct LatLng {
Building geographic bounding boxes in Rust
geospatial
value-types
option
Intermediate
7 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.