Varlock Schema Format
The .env.schema file is a specially formatted .env file that contains Varlock annotations. It is the single source of truth for environment variable types and validation rules.
File: apps/web/.env.schema
Example Schema
Section titled “Example Schema”# @import(../../.env.local, allowMissing=true)# @currentEnv=$NODE_ENV# @defaultRequired=false @defaultSensitive=false# @generateTypes(lang=ts, path=src/env.d.ts)# ---
# @required @type=enum(development,production,test)NODE_ENV=development
# @type=numberBODY_SIZE_LIMIT=10485760
# @type=portELYOS_PORT=3000
# @required @type=urlORIGIN=
# @type=urlAPP_URL=fallback(ref('ORIGIN'),'')
# @required @sensitivePOSTGRES_USER=
# @required @sensitivePOSTGRES_PASSWORD=
# @requiredPOSTGRES_HOST=localhost
# @required @type=url @sensitiveDATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}Global Annotations
Section titled “Global Annotations”At the top of the file, before the # --- line:
@import(path, allowMissing=true)— import another env file@currentEnv=$NODE_ENV— determine the current environment@defaultRequired=false— variables are not required by default@defaultSensitive=false— variables are not sensitive by default@generateTypes(lang=ts, path=...)— TypeScript type generation
Variable Annotations
Section titled “Variable Annotations”| Annotation | Description | Example |
|---|---|---|
@type=string | String value (default) | APP_NAME=ElyOS |
@type=number | Numeric value | BODY_SIZE_LIMIT=10485760 |
@type=number(min=1,max=100) | Numeric value with range | DEMO_RESET_HOUR=3 |
@type=port | Port number (1–65535) | ELYOS_PORT=3000 |
@type=url | URL format | ORIGIN=http://localhost:3000 |
@type=email(normalize=true) | Email address with normalization | SMTP_FROM_EMAIL=noreply@elyos.hu |
@type=enum(a,b,c) | Enumeration type | NODE_ENV=development |
@type=boolean | Boolean value | DEV_MODE=true |
Required
Section titled “Required”@required— required variable, its absence stops the application@required=eq($VAR, value)— conditional requirement
Example of conditional requirement:
# @type=enum(smtp,resend,sendgrid,ses)EMAIL_PROVIDER=smtp
# Only required if EMAIL_PROVIDER=smtp# @required=eq($EMAIL_PROVIDER, smtp)SMTP_HOST=
# @type=port @required=eq($EMAIL_PROVIDER, smtp)SMTP_PORT=587Sensitivity
Section titled “Sensitivity”@sensitive— sensitive data, not logged
# @required @sensitiveBETTER_AUTH_SECRET=
# @required @type=url @sensitiveDATABASE_URL=Default Value
Section titled “Default Value”@default=value— default value if not provided
# @type=port @default=3000ELYOS_PORT=3000Functions
Section titled “Functions”ref(varName)
Section titled “ref(varName)”Reference to another variable:
APP_URL=fallback(ref('ORIGIN'),'')SMTP_FROM_EMAIL=fallback(ref('SMTP_USERNAME'),'')fallback(value1, value2)
Section titled “fallback(value1, value2)”Use the first non-empty value:
# If ORIGIN is empty, use empty stringAPP_URL=fallback(ref('ORIGIN'),'')
# If SMTP_USERNAME is empty, use 'noreply@elyos.hu'SMTP_FROM_EMAIL=fallback(ref('SMTP_USERNAME'),'noreply@elyos.hu')Interpolation
Section titled “Interpolation”Embed variables using ${VAR} syntax:
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}Type Generation
Section titled “Type Generation”The @generateTypes annotation causes Varlock to automatically generate a TypeScript type file:
# @generateTypes(lang=ts, path=src/env.d.ts)Generated file: apps/web/src/env.d.ts
export type CoercedEnvSchema = { NODE_ENV: "development" | "production" | "test"; BODY_SIZE_LIMIT: number; ELYOS_PORT: number; ORIGIN: string; APP_URL?: string; DATABASE_URL: string; // ...};
declare global { namespace NodeJS { interface ProcessEnv extends EnvSchemaAsStrings {} }}This enables type-safe access:
// ✅ Type-safeconst port = process.env.ELYOS_PORT;
// ❌ TypeScript errorconst invalid = process.env.INVALID_VAR;Best Practices
Section titled “Best Practices”- Use descriptive names —
SMTP_HOSTis better thanSH - Group variables — mark categories with comments
- Provide default values — for development environments
- Use conditional requirements — only required variables should be mandatory
- Mark sensitive data — with the
@sensitiveannotation
Next Steps
Section titled “Next Steps”- Runtime validation → — schema.ts in detail
- Infisical integration → — secrets management
- Adding a new variable → — step by step