halostatue

halostatue

Enviable - Robust environment variable conversion

Enviable is a small collection of functions to make working with environment variables easier when configuring Elixir projects. It is designed to work configuration environment loaders like Dotenvy and provides robust value conversion like jetenv.

This has been published several times over the last few weeks, but I just completed a new feature (delimited list conversion) and figure that it’s worth sharing with the community now. This works best when using “12 Factor” configuration via environment variable.

# config/runtime.exs
import Config
import Enviable

client = fetch_env!("CLIENT")
Dotenvy.source([".env", ".env.#{client}", get_env()])

# Before
#
# config :my_app,
#   key: System.fetch_env!("SECRET_KEY"),
#   port: System.fetch_env!("PORT") |> String.to_integer(),
#   ssl: System.get_env("SSL_ENABLED") in ~w[1 true]

# After
config :my_app,
  key: fetch_env!("SECRET_KEY"),
  port: fetch_env_as_integer!("PORT"),
  ssl: get_env_as_boolean("SSL_ENABLED")

Because this is intended for use at configuration startup in a controlled environment, it offers options which would normally be considered unsafe, such as unconstrained atom conversion (fetch_env_as_atom!) while encouraging developers to consider safer options:

# This is allowed but is not recommended.
fetch_env_as_atom!("MY_ATOM_VALUE")
# This is allowed but can still provide unexpected values.
fetch_env_as_safe_atom!("MY_ATOM_VALUE")

# This is better than either of the above—and works as `atom` or `safe_atom` variants:
fetch_env_as_atom!("MY_ATOM_VALUE", allowed: [:red, :green, :blue])

It has been heavily influenced by jetenv for the breadth of conversion, but I have extended its conversion range substantially.

I push for 100% coverage of all branches, and have special attention paid to negative cases. I’m not currently using property checking, but it may be the next thing added. I’ve also tried to make sure that the documentation is comprehensive for all of the supported options, to the point where there’s 30% more @doc lines than there are code lines with doctests for most functions.

https://github.com/halostatue/enviable

Most Liked

halostatue

halostatue

I just released Enviable v1.5, which is mostly a bugfix release, but added a couple of minor features.

I’m not sure when (or if) Enviable 2 will be released, but when it does, the default behaviour of boolean conversion will be to be case-insensitive. To make that transition easier, I added a compile-time option (:enviable, :boolean_downcase) that can be set to :default to match the eventual default and keep your fetch_env_as_boolean! calls simpler).

Although get_env_as_json and related functions documented that the default engine could be configured with :enviable, :json_engine, the code supporting that was incorrect in two ways: it was being evaluated at runtime, not at compile time, and it was using :enviable, :json instead of :enviable, :json_engine. This has been fixed and specifying the JSON engine now allows for an MFA tuple either as a parameter or as a compile configuration.

Changelog

  • Fixed a bug with list conversion for get_env_as_list and get_env_as where support for a :default value was not included.

  • Fixed a bug with :downcase conversions and nil values.

  • Added a compile-time configuration option to change the default boolean :downcase option. The default value is currently false (do not downcase). The next major version of Enviable will change this to :default, as it should not matter whether the matched value is true, TRUE, or True for boolean tests.

  • Added :upcase option to atom and safe_atom conversions.

  • Fixed :json_engine configuration so that it is properly compile-time and referenced. The JSON parsing code was looking this up at runtime under the wrong key.

  • Added support for {m, f, a} specification for :json_engine configuration or the :engine parameter for JSON conversion.

halostatue

halostatue

Over last four weeks, I added a couple of releases of Enviable:

Enviable 2.0.0 (2025-12-26)

This is a breaking change supporting Elixir 1.17+ or higher.

Deprecated functions have been removed: get_env_boolean/2, get_env_integer/2, fetch_env_boolean/2, fetch_env_integer/2, fetch_env_boolean!/2, and fetch_env_integer!/2.

The default value for boolean_downcase and downcase for boolean conversion is :default. This also required changing some conversion types to distinguish between boolean case conversion and atom case conversion.

The default value for case on base16, base32, and hex32 conversion has changed from :upper to :mixed.

Enviable 2.1.0 (2026-01-13)

This is an incremental change that adds no new features to Enviable itself, but as part of a focus on security, a couple of Credo checks have been added. These were developed with the assistance of Kiro.

  • When Enviable.Credo.UnsafeAtom is enabled in .credo.exs, it will report on the use of Enviable functions and conversion options that may result in atom exhaustion. This includes the *_as_atom* and *_as_module* functions, the :atom or :module conversion type, or an encoded conversion which uses :atom or :module. Warnings will not be shown when the :allow option is provided.

  • When Enviable.Credo.UnsafeEval is enabled in .credo.exs, it will report on the use of unsafe code evaluation checks (the *_as_elixir* and *_as_erlang* functions).

As always, Credo checks are advisory and you are best placed to know what the right choice for your application is. It’s dangerous to go alone, take Enviable with you.

halostatue

halostatue

I have forgotten to post two updates released in the last few months, so:

Enviable 1.6 (2025-08-12)

Added support for as_decimal conversions supporting Decimal.

Added JSON support for the built-in JSON module for Elixir 1.18 and later.

Enviable 1.7 (2025-10-15)

Added support for as_timeout conversions supporting timeout values processed through to_timeout/1 on Elixir 1.17 or later. (This feature is not exposed for earlier versions.)

The parser for timeout conversions (this supports 3m2s for 3 minutes and two seconds) was built with LLM assistance using Kiro. The initial prompt used the description in Timeout Values as its core and the parser was built with nimble_parsec.

Note that the next version of Enviable will probably be Enviable 2.0 and it will explicitly only support Elixir 1.17 or later.

Where Next?

Popular in Announcing Top

asiniy
Hey there! I wrote a download elixir package which does exactly what its name about - an easy way to download files. I saw solutions ab...
New
Crowdhailer
The latest release of Ace (0.10.0) includes serving content over HTTP/2. I have started writing a webserver to teach my self more about...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
woutdp
Hi! I wanted to introduce my latest project LiveSvelte. It allows you to render Svelte inside LiveView with end-to-end reactivity. It’s ...
New
oltarasenko
Dear Elixir community, After a year of development, bug fixes, and improvements, we are proudly ready to share the release of Crawly 0.1...
New
Crowdhailer
Raxx is an alternative to Plug and is inspired by projects such as Rack(Ruby) and Ring(Clojure). 1.0-rc.1 is now available. To use it re...
New
aditya7iyengar
Rummage.Ecto and Rummage.Phoenix provide ways to perform Searching, Sorting and Pagination over Ecto queries and Phoenix collections. Fo...
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
benlime
LiveMotion enables high performance animations declared on the server and run on the client. As a follow up to my previous thread A libr...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31142 143
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New

We're in Beta

About us Mission Statement