Functions for working with environment variables in configuration files.
This module provides convenient functions for extracting and converting environment
variables from System.get_env/1. These functions are designed to work seamlessly
with Envious for loading .env files into the system environment.
Typical Workflow
# Load .env file into system environment
".env" |> File.read!() |> Envious.parse!() |> System.put_env()
# Use in config/runtime.exs
use Envious # imports both Envious and Envious.Env
config :my_app, MyApp.Repo,
url: required!("DATABASE_URL"),
pool_size: optional("POOL_SIZE", "10") |> integer!()
config :my_app,
port: required!("PORT") |> integer!(),
host: optional("HOST", "localhost"),
enabled: optional("ENABLED", "true") |> boolean!(),
log_level: optional("LOG_LEVEL", "info") |> atom!(),
allowed_origins: optional("ALLOWED_ORIGINS", "http://localhost") |> list!(),
timeout: optional("TIMEOUT", "30s") |> interval!(:milliseconds)Value Extraction
The module provides three functions for extracting environment variable values:
optional/1- Returns the value ornilif not setoptional/2- Returns the value or a default if not setrequired!/1- Returns the value or raisesSystem.EnvErrorif not set
Note that empty strings ("") are considered valid values and will not trigger
defaults or raise errors.
Type Conversions
All type conversion functions follow the bang (!) convention and will raise
an ArgumentError if the value cannot be converted. This fail-fast approach
is appropriate for configuration that should be validated at application startup.
Error Handling
The module raises two types of errors:
System.EnvError- Raised byrequired!/1when an environment variable is missingArgumentError- Raised by type converters when a value cannot be converted
Available converters:
integer!/1- Convert to integerfloat!/1- Convert to floatboolean!/1- Convert to boolean (handles "true", "false", "1", "0", "yes", "no", "on", "off")atom!/1- Convert to existing atom (safe, won't create new atoms)list!/1- Split string into list (comma-separated by default)list!/2- Split string and transform each elementinterval!/2- Parse time interval strings like "30s", "5m", "2h"uri!/1- Parse URI stringip!/1- Parse IP address (IPv4 or IPv6) into tuple
Examples
# Required value (raises if missing)
required!("DATABASE_URL")
#=> "postgresql://localhost/mydb"
# Optional with default
optional("PORT", "4000")
#=> "4000"
# Optional without default (returns nil if missing)
optional("OPTIONAL_FEATURE")
#=> nil
# Type conversions
optional("PORT", "4000") |> integer!()
#=> 4000
optional("ENABLED", "true") |> boolean!()
#=> true
optional("LOG_LEVEL", "info") |> atom!()
#=> :info
optional("CORS_ORIGINS", "http://localhost,https://example.com") |> list!()
#=> ["http://localhost", "https://example.com"]
# Custom list transformation
optional("PORTS", "4000,4001,4002") |> list!(&integer!/1)
#=> [4000, 4001, 4002]
# Time intervals (defaults to milliseconds like :timer)
optional("TIMEOUT", "30s") |> interval!()
#=> 30000
optional("CACHE_TTL", "5m") |> interval!(:seconds)
#=> 300
Summary
Functions
Converts a string value to an existing atom.
Converts a string value to a boolean.
Converts a string value to a float.
Converts a string value to an integer.
Parses a time interval string and converts it to the specified unit.
Parses an IP address string into a tuple.
Splits a string into a list using a delimiter.
Converts a string module name to a module atom.
Gets an environment variable value, returning nil if not set.
Gets an environment variable value, returning a default if not set.
Gets an environment variable value, raising if not set.
Parses a URI string into a URI struct.
Functions
Converts a string value to an existing atom.
This function uses String.to_existing_atom/1 to safely convert strings
to atoms without creating new atoms dynamically, which prevents potential
memory leaks.
Raises an ArgumentError if the atom does not already exist.
Examples
# Atom exists
:info
atom!("info")
#=> :info
# Atom doesn't exist
atom!("nonexistent_atom_12345")
#=> ** (ArgumentError) atom "nonexistent_atom_12345" does not exist
Converts a string value to a boolean.
Recognizes common boolean representations (case-insensitive):
true: "true", "1", "yes", "on"false: "false", "0", "no", "off"
Raises an ArgumentError if the value is not a recognized boolean string.
Examples
boolean!("true")
#=> true
boolean!("FALSE")
#=> false
boolean!("1")
#=> true
boolean!("0")
#=> false
boolean!("yes")
#=> true
boolean!("no")
#=> false
boolean!("on")
#=> true
boolean!("off")
#=> false
boolean!("maybe")
#=> ** (ArgumentError) could not convert "maybe" to boolean
Converts a string value to a float.
Raises an ArgumentError if the value cannot be parsed as a float.
Examples
float!("3.14")
#=> 3.14
float!("-2.5")
#=> -2.5
float!("42")
#=> 42.0
float!("not a number")
#=> ** (ArgumentError) could not convert "not a number" to float
Converts a string value to an integer.
Raises an ArgumentError if the value cannot be parsed as an integer.
Examples
integer!("42")
#=> 42
integer!("-100")
#=> -100
integer!("not a number")
#=> ** (ArgumentError) could not convert "not a number" to integer
Parses a time interval string and converts it to the specified unit.
Defaults to :milliseconds to match Erlang's :timer module convention.
Supported input formats:
"300"- plain number (treated as milliseconds)"30s"- seconds"5m"- minutes"2h"- hours"1d"- days"500ms"- milliseconds
Supported output units:
:milliseconds(default):seconds:minutes:hours:days
Examples
# Plain numbers default to milliseconds (like :timer.sleep/1)
interval!("300")
#=> 300
interval!("30s")
#=> 30000
interval!("5m")
#=> 300000
# Custom units
interval!("5m", :seconds)
#=> 300
interval!("2h", :minutes)
#=> 120
interval!("1d", :hours)
#=> 24
interval!("invalid")
#=> ** (ArgumentError) could not parse interval "invalid"
@spec ip!(String.t() | nil) :: :inet.ip_address()
Parses an IP address string into a tuple.
Handles both IPv4 and IPv6 addresses. This is commonly used in Phoenix endpoint configuration for binding to specific IP addresses.
Raises an ArgumentError if the IP address cannot be parsed.
Examples
# IPv4
ip!("127.0.0.1")
#=> {127, 0, 0, 1}
ip!("0.0.0.0")
#=> {0, 0, 0, 0}
# IPv6
ip!("::1")
#=> {0, 0, 0, 0, 0, 0, 0, 1}
ip!("2001:db8::8a2e:370:7334")
#=> {8193, 3512, 0, 0, 0, 35374, 880, 29492}
# Invalid
ip!("not an ip")
#=> ** (ArgumentError) could not parse IP address "not an ip"
# Common Phoenix usage
config :my_app, MyAppWeb.Endpoint,
http: [ip: required!("HTTP_IP") |> ip!(), port: 4000]
Splits a string into a list using a delimiter.
Accepts options:
:delimiter- The string to split on (default:","):trim- Whether to trim whitespace from each element (default:true)
Can also accept a transformer function as the second argument to transform each element after splitting. When using a transformer, options can be passed as the third argument.
Examples
list!("a,b,c")
#=> ["a", "b", "c"]
list!("foo, bar, baz")
#=> ["foo", "bar", "baz"]
list!("x:y:z", delimiter: ":")
#=> ["x", "y", "z"]
list!(" a , b , c ", trim: false)
#=> [" a ", " b ", " c "]
list!("")
#=> [""]
# With transformer function
list!("1,2,3", &integer!/1)
#=> [1, 2, 3]
list!("true,false,true", &boolean!/1)
#=> [true, false, true]
# With transformer and options
list!("1:2:3", &integer!/1, delimiter: ":")
#=> [1, 2, 3]
Converts a string module name to a module atom.
This function splits the string on "." and uses String.to_existing_atom/1
for each part, then concatenates them with Module.concat/1. This safely
converts module names without creating new atoms.
Raises an ArgumentError if any part of the module name does not exist as
an atom (typically meaning the module hasn't been compiled/loaded).
Examples
module!("Swoosh.Adapters.Mailgun")
#=> Swoosh.Adapters.Mailgun
module!("String")
#=> String
module!("NonExistent.Module")
#=> ** (ArgumentError) module "NonExistent.Module" does not exist
Gets an environment variable value, returning nil if not set.
This is useful when you want to distinguish between an unset variable and
an empty string, or when nil is an acceptable value in your configuration.
Examples
# Variable is set
System.put_env("MY_VAR", "value")
optional("MY_VAR")
#=> "value"
# Variable is not set
System.delete_env("MY_VAR")
optional("MY_VAR")
#=> nil
# Variable is set to empty string
System.put_env("MY_VAR", "")
optional("MY_VAR")
#=> ""
Gets an environment variable value, returning a default if not set.
Note that empty strings are considered valid values and will not trigger
the default. Only nil (variable not set) will cause the default to be used.
Examples
# Variable is set
System.put_env("MY_VAR", "value")
optional("MY_VAR", "default")
#=> "value"
# Variable is not set
System.delete_env("MY_VAR")
optional("MY_VAR", "default")
#=> "default"
# Variable is set to empty string
System.put_env("MY_VAR", "")
optional("MY_VAR", "default")
#=> ""
Gets an environment variable value, raising if not set.
Raises a System.EnvError if the environment variable is not set or is nil.
Examples
# Variable is set
System.put_env("MY_VAR", "value")
required!("MY_VAR")
#=> "value"
# Variable is not set
System.delete_env("MY_VAR")
required!("MY_VAR")
#=> ** (System.EnvError) could not fetch environment variable "MY_VAR" because it is not set
Parses a URI string into a URI struct.
Raises an ArgumentError if the URI cannot be parsed.
Examples
uri!("https://example.com:8080/path?query=value")
#=> %URI{
#=> scheme: "https",
#=> host: "example.com",
#=> port: 8080,
#=> path: "/path",
#=> query: "query=value"
#=> }
uri!("postgresql://localhost/mydb")
#=> %URI{scheme: "postgresql", host: "localhost", path: "/mydb", ...}