How DMNO uses .env files
DMNO uses .env
files in two ways:
- To scaffold out the initial
schema
in yourconfig.mts
files when your rundmno init
- To set value overrides to be used while resolving your config values
Let’s zoom in on each of these.
Scaffolding the schema
When you run dmno init
, DMNO will look for all .env
files in your project and use them to scaffold out the schema
in your config.mts
files. This includes all .env
files, regardless of being gitignored or checked in, including samples, and environment specific files.
We try to infer as much about each config item as possible by:
- Including related comments as a
description
- Infer the type (
extends
) based on the value for basic types likeboolean
,number
,email
,url
- Set the
value
and not mark it assensitive
if the file was checked into source control. This includes usingvalue: switchBy('NODE_ENV', ...)
if values were found in multiple environment specific files - Set an
exampleValue
from a value from a.env.sample
This automatic scaffolding of your config schema
is meant to be a good starting point, but you should review it and make adjustments as necessary.
Setting overrides via .env
files
Whenever we are resolving your configuration values, dmno will load any .env
files within a .dmno
folder and apply those values as overrides. This means that they will take higher precendence than values set directly in your schema
, and lower precedence than overrides set via actual environment variables passed in from your shell. The overall precedence order from highest to lowest is:
- Environment variables from your shell (e.g.,
ENV_VAR=xyz npm run dev
) - File based overrides
.env.*.local
- applied only ifNODE_ENV
matches*
.env.*
.env.local
.env
- Values set via your
config.mts
schema
While we support it, we do not recommend using complicated .env
file setups like this within dmno! It is supported purely to ease migration. Instead we recommend migrating this logic into the schema itself - setting values using functions and helpers like switchBy
to express more complex overriding behaviour, and using plugins to load sensitive values securely. See our Schema Authoring guide for more details.
We do, however, recommend using a single gitignored .env.local
file to store any overrides you want to apply locally. This can be useful for short-lived temporary settings that you may want to toggle during development - like flags that enable certain debugging related features. It’s also where we recommend storing sensitive keys that you don’t want checked into version control; values that in deployed environments you would set via actual environment variables.
If you’re using plugins to handle your sensitive config values, you would store the sensitive keys that enable those plugins in your .env.local
file. For example, for our 1Password plugin, the 1Password service account token, or for our Encrypted Vault plugin, the key used to decrypt the vault file. This allows you the simplicity of only having to worry about one single config item, while keeping everything secure.
Resolving config and outputting to .env format
You can use the dmno resolve
command to load the resolved config for a service and output it in .env
file format. This is useful for quickly exporting all your config values to a file for use in other systems, especially in some serverless environments where you may need to set a lot of environment variables at once and you don’t have as much control over the running process as you do locally.
Consider the following example where we want to load an .env
file for use in Supabase Edge Functions.
You can run the following command to load the resolved config for your api
service and output it to a file.
If you want to do this with a single command, you can combine them like this:
This has the added benefit of writing no file, so you don’t need to worry about deleting it later or accidentally checking it into source control.