Get started in 5 minutes

How do you get a secret from AWS SSM Parameter Store or Azure Key Vault into a running app? Install the Envilder CLI, map the secret to a variable name in envilder.json, and start your app with envilder exec, which hands the value to the process without writing a .env file. The whole setup takes about five minutes once your cloud credentials work.

What you will do

  1. Install the envilder CLI.
  2. Push one test secret to AWS SSM Parameter Store or Azure Key Vault with envilder, which also writes envilder.json.
  3. Check the envilder.json it created: it maps a variable name to the secret, never to the value.
  4. Start a small Node.js app with envilder exec and check that it receives the value.

Prerequisites

  • Node.js 22.12 or later.
  • AWS SSM: the AWS CLI with working credentials (aws configure, or aws sso login for SSO profiles) and an identity allowed to call ssm:GetParameter on the parameters you map. If a SecureString parameter is encrypted with a customer-managed KMS key, the identity also needs kms:Decrypt on that key. AWS SSM setup
  • Azure Key Vault: an existing Key Vault, the Azure CLI signed in with az login, and the Key Vault Secrets User role on the vault (or an access policy with Get on secrets). Envilder authenticates with DefaultAzureCredential, so a managed identity or environment credentials work too. Azure Key Vault setup

Step 2 creates a secret, which needs write access (ssm:PutParameter, or Key Vault Secrets Officer). If the secret already exists, skip it and write envilder.json by hand as shown in step 3.

1. Install the CLI

Install envilder globally. If you prefer not to install it, prefix every command in this guide with npx.

npm install -g envilder
pnpm add -g envilder
npx envilder --version

Check that the command is on your PATH. It prints the version:

envilder --version
0.20.0

2. Push a test secret

Choose your provider. One envilder command stores the secret in the vault and records the mapping in envilder.json, so this step needs neither the AWS CLI nor the Azure CLI. The guide uses a single secret: the database password of a development environment. The value stays in your shell history; for real secrets, push from a .env file with push mode instead.

envilder --push --provider=aws --profile=default \
  --key=DB_PASSWORD --value=local-dev-password \
  --secret-path=/my-app/dev/db-password

On AWS, --provider=aws and --profile are optional: aws is the default provider, and without --profile Envilder uses the AWS default credential chain. The profile is a local choice and is not written to envilder.json.

envilder --push --provider=azure --vault-url=https://my-vault.vault.azure.net \
  --key=DB_PASSWORD --value=local-dev-password \
  --secret-path=my-app-dev-db-password

Key Vault names only allow letters, digits and hyphens. Envilder turns slashes into hyphens and drops a leading slash before calling Azure, so "/my-app/dev/db-password" would resolve the same secret. Anything else is sent as written.

3. Check envilder.json

The push created envilder.json in the current directory, or added the entry if the file already existed. Each key is the variable name your app reads, and each value is the identifier of the secret in your vault. For Azure it also wrote $config with provider and vaultUrl; AWS needs no $config.

envilder.jsonjson
{
  "DB_PASSWORD": "/my-app/dev/db-password"
}
envilder.jsonjson
{
  "$config": {
    "provider": "azure",
    "vaultUrl": "https://my-vault.vault.azure.net"
  },
  "DB_PASSWORD": "my-app-dev-db-password"
}

The file holds secret paths, never values, so commit it with your code. Editors validate envilder.json through SchemaStore without a $schema line. To push a secret without touching the map file, add --no-map-update.

4. Run your app with envilder exec

Create a small script that reads the variable, then start it through Envilder. Everything after -- is your command, passed as is, without a shell.

app.jstypescript
const password = process.env.DB_PASSWORD;
console.log(
  password
    ? `DB_PASSWORD loaded (${password.length} characters)`
    : 'DB_PASSWORD missing',
);
envilder exec -- node app.js

Expected output. The first line is Envilder on stderr; the second is your app on stdout:

envilder: 1 secret resolved (aws) → node …
DB_PASSWORD loaded (18 characters)
envilder: 1 secret resolved (azure, vault=my-vault.vault.azure.net) → node …
DB_PASSWORD loaded (18 characters)

Envilder resolves every mapped secret, then starts the command with those values added to its environment. Nothing is written to disk. If any secret is missing, empty or unreadable, the command does not start and envilder exits with code 125; otherwise it exits with the code of your command.

To make this the normal way to start the project, put it in a package.json script and keep running npm run dev:

package.jsonjson
{
  "scripts": {
    "dev": "envilder exec -- node app.js"
  }
}

Alternative: write a .env file

Some tools only read a file, such as a Docker Compose env_file or an IDE run configuration. For those, pull the secrets into a .env file instead. Without flags, envilder reads envilder.json and writes .env in the current directory:

envilder

Expected output with AWS, followed by the file it writes:

☁ AWS identity · account=123456789012 · region=eu-west-1 · profile=default

🪙  RESOLVING SECRETS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ✓ DB_PASSWORD         → ***************ord

⭐ LEVEL CLEARED  —  1/1 secrets loaded · .env written
.envdotenv
DB_PASSWORD=local-dev-password
⚠️
The .env file contains the real secret values: add it to .gitignore and delete it when you no longer need it. Unlike exec, pull skips a secret that does not exist with a warning and still writes the others.

Common first-run errors

Each block shows the text envilder prints. With exec, every one of these exits with code 125 and your command never starts.

No map file found

No map file found. Provide --map or create envilder.json in the current directory.

envilder looks for envilder.json in the current directory. Run it from the project root, or pass --map=path/to/envilder.json.

No AWS credentials

💥 GAME OVER — some secrets could not be fetched
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ✗ DB_PASSWORD         → ********************ord

  ⮕ WHY?
     Could not load credentials from any providers

The AWS SDK found no credentials. Run aws configure, or aws sso login for an SSO profile. To use a named profile, pass --profile=name or set "profile" in $config.

Access denied by AWS

User: arn:aws:sts::123456789012:assumed-role/<role>/<session> is not authorized to perform: ssm:GetParameter on resource: arn:aws:ssm:eu-west-1:123456789012:parameter/my-app/dev/db-password …

The credentials work but the identity cannot read that parameter. Allow ssm:GetParameter on the parameter ARN, plus kms:Decrypt when the parameter uses a customer-managed key.

Secret not found

  ✗ DB_PASSWORD         → ********************ord

  ⮕ WHY?
     not found

The identifier or the region is wrong. For AWS, Envilder takes the region from AWS_REGION, then AWS_DEFAULT_REGION, then the profile, and falls back to us-east-1. Compare with aws ssm get-parameter --name /my-app/dev/db-password using the same profile. For Azure, check the secret name in the vault.

Azure without a vault URL

vaultUrl is required when using Azure provider. Set it in $config.vaultUrl in your map file or via --vault-url flag.

Add "vaultUrl": "https://<vault-name>.vault.azure.net" to $config, or pass --vault-url.

Options placed before exec

error: Put envilder options after "exec": envilder exec --map=envilder.json -- node …

Options written before exec are rejected rather than ignored. Move them after exec, as the message shows.

--envfile used with exec

error: --envfile cannot be used with exec: exec mode never reads or writes a .env file.

exec never writes a file. Remove --envfile, or use pull (envilder --envfile=.env) when you need the file.

Next steps