RFC: Env variables management #3109
Replies: 2 comments
-
Validation solutions
As we're already using
const PASSWORD = env.get('DB_PASSWORD')
// Throws an error if the DB_PASSWORD variable is not set (optional)
.required()
// Decode DB_PASSWORD from base64 to a utf8 string (optional)
.convertFromBase64()
// Call asString (or other APIs) to get the variable value (required)
.asString();
// Read in a port (checks that PORT is in the range 0 to 65535)
// Alternatively, use a default value of 5432 if PORT is not defined
const PORT = env.get('PORT').default('5432').asPortNumber() ⬆️ this example looks nice but it'll only work with Node.js. Not with Vite. Not with Next.js. Not with CRA. The issue is that on the frontend you need to explicitly provide import { from } from 'env-var';
const { get } = from({
SOME_VALUE: process.env.NEXT_PUBLIC_SOME_VALUE,
PORT: process.env.NEXT_PUBLIC_PORT
})
const SOME_VALUE = get('SOME_VALUE')
.required()
.convertFromBase64()
.asString();
const PORT = get('PORT')
.default('5432')
.asPortNumber(); It's still quite good and I 👍 this. Env loading solutions
We should also use We also want to load multiple files in a specific order – similar to what Next.js does. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the RFC! It looks great and I have a couple of comments. Firstly, we have to consider who will be using our dashboard. Currently, I think there are at least 3 groups:
With this in mind, I’m wondering if:
Other than that I think I quite like an |
Beta Was this translation helpful? Give feedback.
-
Each FE project in Saleor has different way of handling env variables and validating them. Each has some upsides and downsides, we should rethink our approach so that our apps are less error-prone to user error (invalid env vars, missing configuration, etc.).
Current usage
Saleor Core
Described on docs.saleor.io.
For macOS/Linux: we recommend using
dotenv
to set env variables. We'll skip how validation is done because core is written in Python.Saleor Dashboard
Saleor Dashboard doesn't use any package for loading environment variables. Instead,
loadEnv
from Vite is used to load every env variable:https://github.com/saleor/saleor-dashboard/blob/main/vite.config.js#L13
After that, we select a handful of env vars to be loaded into
process.env
: https://github.com/saleor/saleor-dashboard/blob/main/vite.config.js#L130:L140This is done due to security concerns.
Internally, Vite uses
dotenv
to load environment variables from.env
files. Previously, we've recommended usingdirenv
to load the environment variables.React Storefront
React Storefront is a monorepo, so configuration will be different from a single-repo project.
For entire monorepo it uses
env-cmd
in package.json scripts to load environment variables from.env
and.env.local
files: https://github.com/saleor/react-storefront/blob/canary/package.json#L17Those files are located at the root of monorepo.
Each project can be also run independently, it can have its own
.env
and.env.local
files that reference environment variables from the root of monorepo (e.g. in./.env
we declare variableTEST
we can reuse that variable in./app/my-app/.env
like that:OTHER_ENV=$TEST
). Those projects can be run from their own directory, for example when running tests. Because of that, we've developed a special package (env-vars
) that loads env variables in correct order: https://github.com/saleor/react-storefront/tree/canary/packages/env-varsenv-vars
uses internallydotenv
,dotenv-expand
andfind-config
: https://github.com/saleor/react-storefront/blob/canary/packages/env-vars/package.jsonSaleor App Template
It uses default Next.js behavior for loading environment variables.
TL;DR: It loads envs from
.env.local
, but only envs that start withNEXT_PUBLIC_
to the frontend (by default it's only visible in Node.js environment - aka API Routes,getStaticProps
, etc.)Main idea
.env
and.env.local
files..env
is commited into the repository.env
files, they should load environment variables from the root of monorepo as well (like we do inreact-storefront
right now).env
file update that they need to restart dev server in order to see changes / re-build the projectValidation solutions
zod schema
Inspired by
create-t3-app
.We declare a schema for server and frontend environment variables using
zod
. See exampleWe create two files with logic for loading backend and frontend env variables. They can be included for example in
next.config.js
to be validated when a project is stared. Validation can also be skipped when a special env is passed (useful for Docker):To use the env variable you import it from the file that sets them up:
Sum-up
zod
, we can have many custom rules for validationUse env-vars package
Similar to zod, except it can be used as a direct replacement from using
process.env
. It also doesn't require additional files for set-up:It has many built-in validators for most env vars use cases, but a custom accessor can also be written.
Sum-up
process.env
Env loading solutions
Custom env vars package
We could re-use the package from
react-storefront
that loads the env variables in correct order.Using plain dotenv
This doesn't require any changes, we keep on using dotenv either via directly including this package or by a pre-build solution in one of our tools (e.g. Next.js, Vite)
dotenv
packageNot using any package for loading env vars
This is something we already do in core. You could argue that the job of loading environment variables should be on user, because it depends based on their environment (e.g. Windows vs Docker vs macOS).
To make this easier, we could recommend our users to use the
direnv
package that loads environment variables from.env
or.envrc
file. It uses a standard way of our uses shell for loading env variables (e.g.export XYZ=123
in bash/zsh)..env
is loaded automatically, vs it requires installing an external software and runningdirenv allow
on every change).env
file changeBeta Was this translation helpful? Give feedback.
All reactions