Getting started
This quick start guide walks you through setting up envarna in your project, creating your first settings classes, and gradually layering in validation and more advanced features.
Installation
npm install envarna
Basic Usage
Create settings classes
Settings are grouped into classes, each representing a coherent domain of configuration. For example, general application settings might live in AppSettings
, while database settings go in MongoSettings
.
// settings/app.ts
import { BaseSettings, settings } from 'envarna';
export class AppSettings extends BaseSettings {
@settings.string()
name: string;
@settings.boolean()
debug: boolean = false;
}
// settings/page.ts
import { BaseSettings, settings } from 'envarna';
export class OtherSettings extends BaseSettings {
@settings.number()
numRetries: number;
}
Collect your settings into a proxy
This is optional but highly recommended.
Use createSettingsProxy()
to define a centralized settings
object. This pattern defers loading until first access and enables test overrides.
// settings/index.ts
import { createSettingsProxy } from 'envarna';
import { AppSettings } from './app';
import { PageSettings } from './page';
export const settings = createSettingsProxy({
app: () => AppSettings.load(),
other: () => OtherSettings.load(),
});
Use your settings in application code
// main.ts
import { settings } from './settings';
if (settings.app.debug) {
console.debug(`Retry count ${settings.other.numRetries}`);
}
Provide environment variables
Envarna loads the settings with values from environment variables. The names of these variables are derived from:
- The class name (e.g.,
OtherSettings
) is used as a prefix, withSettings
stripped and converted to uppercase:OTHER_
- Each field name (e.g.,
numRetries
) is transformed from camelCase to uppercase with underscores:NUM_RETRIES
- The full environment variable becomes:
APP_NAME
,OTHER_NUM_RETRIES
By default, envarna loads variables from first from the process environment (process.env
) and secondly (if it exists) from .env
file using dotenv
.
APP_NAME=MyApp
APP_DEBUG=true
OTHER_NUM_RETRIES=50
If a required variable is missing (without a default) or is malformed, envarna will throw a validation error at startup.
Beyond the basics
You can expand your schema using Zod-compatible validators with a v
extension. You can also override the naming convention by providing an alias.
// settings/service.ts
import { BaseSettings, settings, v } from 'envarna';
export class ServiceSettings extends BaseSettings {
@settings(v.string().length(10))
apiKey: string;
@settings(v.url())
@alias('ACME_API_URL')
endpoint: string;
}
SERVICE_API_KEY=abcdefghij
AMCE_API_URL=https://api.example.com
What is v
?
Most of the time you will decorate your setting field with one of:
@setting.string()
@setting.number()
@setting.boolean()
@setting.date()
@setting.array()
@setting.object() // in progress
If you want more control over the validation, use v
:
@setting(v.number().int().min(10).max(100).default(42))
v
is for "validation". It is a light extension of z
from Zod designed for use in a settings environment.
- automatic coercion (e.g.
v.number()
accepts strings like "42") - access to Zod validations e.g.:ts
@setting(v.url()) @setting(v.email()) @setting(v.string().startsWith('aaa').includes('mmm').length(15).toUpperCase())
- handling for arrays (and soon objects)
You can still use raw Zod if needed, just remember to be aware of coercion:
@settings(v.date().min(new Date("1984-01-01")))
// is the same as...
@settings(z.coerce.date().min(new Date("1984-01-01")))
See the sections (string formats, numbers, etc.) under Zod's Defining schemas for more details.
Discover and Document Your Settings
Once your settings classes are defined, you can explore and document them with envarna's CLI.
To list all known settings:
npx envarna list
To generate a .env.template
showing required and optional variables:
npx envarna env > .env.template
This helps you avoid missing variables and makes it easier to onboard new developers or deploy to new environments.
What’s Next?
For many projects, this is all you need. But when config complexity increases, envarna is ready:
- Load values from external sources like GCP Secret Manager
- Use conditional logic (e.g., different loaders based on env flags)
- Inject test values safely with
.overrideForTest()
- Generate
.env.template
and validation reports withnpx envarna
See Testing Best Practices
and Advanced Loading
guides for more.