dotenv/lib.rs
1//! Load and use environment variables from `.env` files.
2//!
3//! # Overview
4//!
5//! This crate parses `.env` files with variable substitution support:
6//! `$VAR`, `${VAR}`, `${VAR:-default}`. It provides both convenience
7//! functions (for typical usage) and a builder-style [`Dotenv`] type
8//! (for fine-grained control).
9//!
10//! # Quick start
11//!
12//! ```no_run
13//! dotenv::load().ok();
14//!
15//! for (key, value) in dotenv::vars() {
16//! println!("{key}={value}");
17//! }
18//! ```
19//!
20//! # Available entry points
21//!
22//! | Task | Function / Type |
23//! |---|---|
24//! | Load `.env` automatically | [`load()`], [`var()`], [`vars()`] |
25//! | Load a specific file | [`from_path()`], [`from_filename()`] |
26//! | Load from a custom source | [`from_read()`] |
27//! | Builder with control over behaviour | [`Dotenv`] |
28
29mod dotenv;
30mod error;
31mod parse;
32
33pub use crate::dotenv::Dotenv;
34pub use crate::error::Error;
35pub type Result<T> = std::result::Result<T, Error>;
36
37use std::env;
38use std::ffi;
39use std::fs;
40use std::io;
41use std::io::Read;
42use std::path::Path;
43use std::path::PathBuf;
44use std::sync::Once;
45
46static LOAD: Once = Once::new();
47
48/// Get the value for an environment variable.
49///
50/// Automatically loads `.env` on first call (if present and not yet loaded).
51/// Values are read from the **current process environment**, not directly from
52/// the `.env` file — so any value set by a previous caller or the shell is visible.
53///
54/// # Errors
55///
56/// Returns [`Error::Env`] if the variable contains non-unicode data.
57///
58/// # Examples
59///
60/// ```no_run
61/// let value = dotenv::var("HOME").unwrap();
62/// println!("{}", value);
63/// ```
64pub fn var<K: AsRef<ffi::OsStr>>(key: K) -> Result<String> {
65 LOAD.call_once(|| {
66 load().ok();
67 });
68
69 env::var(key).map_err(Error::from)
70}
71
72/// Return an iterator of `(key, value)` pairs for all environment variables
73/// of the current process.
74///
75/// Automatically loads `.env` on first call. The returned iterator is a
76/// snapshot of the process environment at the time of invocation —
77/// subsequent modifications are not reflected.
78///
79/// # Examples
80///
81/// ```no_run
82/// use std::io;
83///
84/// for (key, value) in dotenv::vars() {
85/// println!("{key}={value}");
86/// }
87/// ```
88pub fn vars() -> env::Vars {
89 LOAD.call_once(|| {
90 load().ok();
91 });
92
93 env::vars()
94}
95
96fn find<P: AsRef<Path>>(filename: P) -> Result<PathBuf> {
97 let filename = filename.as_ref();
98 env::current_dir()?
99 .ancestors()
100 .map(|dir| dir.join(filename))
101 .find(|path| path.is_file())
102 .ok_or_else(Error::not_found)
103}
104
105/// Load the `.env` file from the current directory or its parents.
106///
107/// Searches upward from the current working directory until `.env` is found.
108/// The first call loads variables; subsequent calls are no-ops through
109/// [`Dotenv::load`] (existing variables are preserved).
110///
111/// # Errors
112///
113/// Returns [`Error::Io`] if no `.env` file is found or it cannot be read.
114///
115/// # Examples
116///
117/// ```no_run
118/// dotenv::load().ok();
119/// ```
120pub fn load() -> Result<PathBuf> {
121 let path = find(".env")?;
122 from_path(&path).map(|vars| {
123 vars.load();
124 path
125 })
126}
127
128/// Create [`Dotenv`] from the specified file.
129///
130/// Searches upward from the current working directory for the given filename.
131///
132/// # Errors
133///
134/// Returns [`Error::Io`] if the file is not found or cannot be read.
135pub fn from_filename<P: AsRef<Path>>(filename: P) -> Result<Dotenv> {
136 let path = find(filename)?;
137 from_path(path)
138}
139
140/// Create [`Dotenv`] from the specified path.
141///
142/// # Errors
143///
144/// Returns [`Error::Io`] if the file cannot be read.
145pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Dotenv> {
146 let file = fs::File::open(path)?;
147 from_read(file)
148}
149
150/// Create [`Dotenv`] from any [`Read`] implementor.
151///
152/// This is useful for loading environment variables from in-memory buffers,
153/// IPC streams, or network connections.
154///
155/// # Errors
156///
157/// Returns [`Error::Io`] if reading from the source fails.
158///
159/// # Examples
160///
161/// ```
162/// use std::io::Cursor;
163///
164/// let input = Cursor::new(b"FOO=bar\nBAZ=qux\n");
165/// let dotenv = dotenv::from_read(input).unwrap();
166/// for (key, value) in dotenv.iter() {
167/// println!("{key}={value}");
168/// }
169/// ```
170pub fn from_read<R: Read>(read: R) -> Result<Dotenv> {
171 let mut buf = String::new();
172 let mut reader = io::BufReader::new(read);
173 reader.read_to_string(&mut buf)?;
174
175 Ok(Dotenv::new(buf))
176}