Last week I tagged version 4.0.0 of envalid, a Node library for environment variable validation that helps you avoid several environment variable antipatterns. For those who have been using it (and may be wary of a major version bump) I wanted to do a quick write-up of the notable additions. The backwards-compatible changes are small, but there is some great stuff in the latest version!
Calling envalid "my" library is no longer accurate, as the last few months have brought contributions from several others. In particular @SimenB contributed most of the new code that culminated in this latest major release 👏.
What's not new
I've never really described envalid's features in detail here, but briefly, here are some of the things it handles for you out of the box:
- Allows you to declaratively describe the environment your app expects to run in
- Provides several useful env var validators (number, json, email, etc) so that the plain strings you
get from
process.env
are converted to a useful format centrally, rather than all across your app - It's super easy to define custom validators if the built-in ones don't cover all the shapes of your data
- Wraps the awesome
dotenv
package, so you can drop your development/testing default values in a.env
file instead of hardcoding them somewhere. - Handy shorthands
env.isDev
,env.isProduction
, andenv.isTest
to replace theif (process.env.NODE_ENV === 'production')
checks that tend to get strewn about.
New in v4
Two nice little additions are the use of prettier
for code formatting and new host
and port
validators. In my experience, hosts and ports are extremely common env vars so it's nice to have
some extra validation baked in for these.
The major (and only breaking) change is to envalid's "strict mode", which gives you some extra guarantees about your validated environment object. In v4, strict mode will throw if you try to set, or even access, an invalid property on your environment object. If the mistake was a simple typo, envalid will helpfully suggest a related property that you may have meant.
The following (contrived) example shows how this helps in practice. Note how well it works when destructuring your env imports– the errors happen at startup time, rather than later on during the execution of your server route.
// Oops! I forgot a 'T' in there.
// But in v4.x envalid will throw instead of returning `undefined`
const { STRIPE_SECRE_KEY } = require('path/to/my/env/object')
app.get('/customer/info', (req, res) => {
const stripe = require('stripe')(STRIPE_SECRE_KEY)
stripe.customers.retrieve(req.user.customerId)
.then(customer => res.json(customer))
})
The future
It feels like envalid is "mostly done", but I probably would have said the same thing three months ago, before all of the features above landed. It's exciting to see adoption pick up (currently just a shade under 10k monthly downloads) and lots of great community feedback and contributions. Here are a few random ideas I've thought of that might be useful in the future:
- A custom eslint rule to warn when accessing process.env directly – this would in effect force you to access the cleaned env object that you get from envalid.
- Built-in support for designating env vars that are used client-side, and returning a separate validated object that you can import from your webpack config.
- Bindings for Reason
If you have any other ideas, please drop by the envalid issue tracker!