<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Veerawat</title>
    <description>The latest articles on Forem by Veerawat (@veerawat).</description>
    <link>https://forem.com/veerawat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1229969%2F7133caa6-2228-4f8f-bea2-7659bacb3919.png</url>
      <title>Forem: Veerawat</title>
      <link>https://forem.com/veerawat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/veerawat"/>
    <language>en</language>
    <item>
      <title>Load and Map Environment Variables in Rust with dotenvy, serde, and envy</title>
      <dc:creator>Veerawat</dc:creator>
      <pubDate>Tue, 13 Jan 2026 05:56:35 +0000</pubDate>
      <link>https://forem.com/veerawat/load-and-map-environment-variables-in-rust-with-dotenvy-serde-and-envy-26a9</link>
      <guid>https://forem.com/veerawat/load-and-map-environment-variables-in-rust-with-dotenvy-serde-and-envy-26a9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yf3gbt1n4bssd5wmhe5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7yf3gbt1n4bssd5wmhe5.png" alt="Mapping environment variables into a Rust configuration struct" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Environment variable management is an important part of configuring applications. In Rust, we can load variables from a .env file and map them into a struct for type-safe access using the crates dotenvy, serde, and envy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Install Dependencies
&lt;/h2&gt;

&lt;p&gt;First, add the dotenvy crate to your project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cargo add dotenvy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then check your Cargo.toml to confirm it’s installed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ugtry6jbavu4a7pvbqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ugtry6jbavu4a7pvbqv.png" alt="dotenvy" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Create the .env File
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the project root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ENVIRONMENT="development"
APP_USER="test"
PORT=555
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzt0qr923z2rr3ah35nat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzt0qr923z2rr3ah35nat.png" alt="folders" width="596" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading Environment Variables Manually
&lt;/h2&gt;

&lt;p&gt;Here’s how you can load variables from the .env file using dotenvy and read them manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use std::env;

fn main() {
    dotenvy::dotenv().ok(); // Load from .env

    let environment = env::var("ENVIRONMENT").expect("ENVIRONMENT not set");
    let app_user = env::var("APP_USER").expect("APP_USER not set");
    let port = env::var("PORT").expect("PORT not set");

    println!("ENVIRONMENT = {}", environment);
    println!("USER = {}", app_user);
    println!("PORT = {}", port);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expect calls here handle errors in a fail-fast style, ensuring the variables exist and are ready to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping to a Struct with serde
&lt;/h2&gt;

&lt;p&gt;Instead of manually extracting each value, you can declare a Rust struct and derive Deserialize from serde to handle the data:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cargo add serde --features derive&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This enables the required derive feature. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serde = {version="1.0.228", features = ["derive"]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use std::env;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Config {
    environment: String,
    app_user: String,
    port: u16,
}

fn main() {
    dotenvy::dotenv().ok(); // Load from .env

    let config = Config {
        environment: env::var("ENVIRONMENT").expect("ENVIRONMENT not set"),
        app_user: env::var("APP_USER").expect("APP_USER not set"),
        port: env::var("PORT").expect("PORT not set"),
    };

    println!("ENVIRONMENT: {}", config.environment);
    println!("APP_USER: {}", config.app_user);
    println!("PORT: {}", config.port);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method still manually maps values but benefits from typed fields thanks to serde.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatically Mapping with envy
&lt;/h2&gt;

&lt;p&gt;To avoid mapping environment variables one by one, you can use the envy crate. It automatically deserializes environment variables into a struct.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cargo add envy&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Config {
    environment: String,
    app_user: String,
    port: u16,
}

fn main() {
    dotenvy::dotenv().ok(); // Load from .env

    let config: Config = envy::from_env().expect("Failed to load config");

    println!("{:?}", config.app_user);
    println!("{:?}", config.environment);
    println!("{:?}", config.port);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;⚠️Warning!!&lt;/strong&gt;&lt;br&gt;
Before using &lt;code&gt;envy&lt;/code&gt;, make sure your environment variable names match your struct fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note &amp;amp; Summary&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dotenvy loads environment variables from a .env file into your Rust app.&lt;/li&gt;
&lt;li&gt;envy maps those environment values to a Rust struct.&lt;/li&gt;
&lt;li&gt;serde handles the deserialization and type conversion for your struct fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination keeps your configuration clean and type-safe, which is especially useful as the number of environment variables grows.&lt;/p&gt;

&lt;p&gt;You can find the full example and source code in this GitHub repository: &lt;a href="https://github.com/Veerawat/rust-dotenvy-envy-example" rel="noopener noreferrer"&gt;code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>rust</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
