Environment Variables
Manage sensitive information using .env files.
Environment variables store sensitive values like API keys, database URLs, and Discord credentials outside of your codebase. They are loaded at startup and kept separate from version-controlled files to prevent accidental exposure.
Standard File
Robo.js projects use a .env file in the project root:
# .env
# Discord Credentials
DISCORD_CLIENT_ID="your_application_id"
DISCORD_TOKEN="your_bot_token"
# Custom variables
EXAMPLE_VARIABLE="Sshh, this is a secret!"Variables are key-value pairs separated by an equals sign. Access them in code using process.env:
export default () => {
return process.env.EXAMPLE_VARIABLE ?? 'No secret found!'
}export default () => {
return process.env.EXAMPLE_VARIABLE ?? 'No secret found!'
}Warning: Be careful where you use process.env in your code. Do not expose sensitive values in logs or error messages.
Security
Environment variables follow well-established practices for keeping secrets safe:
- Access control: You control who can view your
.envfile and its contents. - Audit trails: Changes to the
.envfile can be tracked separately from code changes. - Isolation: Sensitive information stays separate from your source code.
- Version control: The
.envfile is excluded from Git by default. Robo.js includes an optimized.gitignore.
Note: Doppler provides a secure way to store and manage secrets, especially when sharing across teams.
Modes and Variables
Projects with multiple environments can use mode-specific .env files. Suffix the filename with the mode name, and Robo.js will load the correct file automatically based on the active Mode.
# .env.production
DEBUG_STUFF="false"
EXAMPLE_VARIABLE="Hello, production!"# .env.development
DEBUG_STUFF="true"
EXAMPLE_VARIABLE="Hello, development!"Running robo dev loads .env.development, while robo start loads .env.production:
export default () => {
return process.env.EXAMPLE_VARIABLE ?? 'No secret found!'
}export default () => {
return process.env.EXAMPLE_VARIABLE ?? 'No secret found!'
}Env API
Robo.js manages environment variables automatically, but it also exports an Env API for more control.
import { Env } from 'robo.js'import { Env } from 'robo.js'| Method | Description |
|---|---|
| Constructor | Creates a structured schema. |
load() | Load the .env file. |
loadSync() | Load the .env file synchronously. |
data() | Get all loaded variables. |
Loading Variables
Robo.js loads your .env file automatically at startup. Access values through process.env:
export default () => {
console.log(process.env.EXAMPLE_VARIABLE)
}export default () => {
console.log(process.env.EXAMPLE_VARIABLE)
}You can also load environment variables manually:
import { Env } from 'robo.js'
export default async () => {
await Env.load()
// Synchronous alternative
Env.loadSync()
console.log(process.env.EXAMPLE_VARIABLE)
// View only variables loaded by Robo (excludes system variables)
console.log(Env.data())
}import { Env } from 'robo.js'
export default async () => {
await Env.load()
// Synchronous alternative
Env.loadSync()
console.log(process.env.EXAMPLE_VARIABLE)
// View only variables loaded by Robo (excludes system variables)
console.log(Env.data())
}Customize loading behavior with an options object:
await Env.load({
// The mode to load environment variables for
mode: 'production',
// Whether to overwrite existing environment variables
// Can be a boolean or an array of keys to overwrite
overwrite: true,
// The path to the environment file. Defaults to `.env`
path: '/path/to/.env'
})await Env.load({
// The mode to load environment variables for
mode: 'production',
// Whether to overwrite existing environment variables
// Can be a boolean or an array of keys to overwrite
overwrite: true,
// The path to the environment file. Defaults to `.env`
path: '/path/to/.env'
})Both load() and loadSync() modify process.env directly and return an object with the loaded variables.
Schema Builder
The Env constructor creates a structured schema for your environment variables, providing organized access and default values:
import { Env } from 'robo.js'
const env = new Env({
discord: {
clientId: {
env: 'DISCORD_CLIENT_ID'
},
token: {
env: 'DISCORD_TOKEN'
}
},
example: {
default: 'Nothing to see here',
env: 'EXAMPLE_VARIABLE'
}
})import { Env } from 'robo.js'
const env = new Env({
discord: {
clientId: {
env: 'DISCORD_CLIENT_ID'
},
token: {
env: 'DISCORD_TOKEN'
}
},
example: {
default: 'Nothing to see here',
env: 'EXAMPLE_VARIABLE'
}
})Access variables through the schema:
// Use get() to access variables
console.log(env.get('example'))
// Use dot notation for nested variables
console.log(env.get('discord.clientId'))
// Equivalent to: process.env.DISCORD_CLIENT_ID ?? 'Nothing to see here'// Use get() to access variables
console.log(env.get('example'))
// Use dot notation for nested variables
console.log(env.get('discord.clientId'))
// Equivalent to: process.env.DISCORD_CLIENT_ID ?? 'Nothing to see here'This approach centralizes your environment variable references. Renaming a variable in .env requires updating only the schema, not every process.env reference in your code.
The schema also provides type checking with TypeScript.
