Skip to content

Commit 9957795

Browse files
committed
feat: add native .env file loading support
1 parent 9eb7001 commit 9957795

File tree

6 files changed

+1059
-0
lines changed

6 files changed

+1059
-0
lines changed

examples/env-variables/.env

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Application Configuration
2+
APP_NAME=Express Env Example
3+
APP_ENV=development
4+
5+
# Server Configuration
6+
PORT=5000
7+
DEBUG=true
8+
9+
# API Configuration
10+
API_URL=https://api.example.com
11+
MAX_ITEMS=100
12+

examples/env-variables/README.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# env-variables
2+
3+
This example demonstrates how to use Express's built-in environment variable loading from `.env` files.
4+
5+
## Features
6+
7+
- Load environment variables from `.env` files without third-party packages
8+
- Optional **file watching** for automatic reloads during development
9+
- Support for environment-specific files (`.env.development`, `.env.production`)
10+
- Cascading configuration with `.env.local` overrides
11+
- Support for comments and empty lines
12+
- Quoted values (single and double quotes)
13+
- Escaped characters (`\n`, `\t`, etc.)
14+
- Multi-line values with backslash continuation
15+
- Values with special characters and equals signs
16+
17+
## Run the example:
18+
19+
```bash
20+
$ node index.js
21+
```
22+
23+
Then visit [http://localhost:3000](http://localhost:3000) in your browser.
24+
25+
## Usage
26+
27+
### Basic Usage (No Watch Mode)
28+
29+
Load environment variables once at startup. Recommended for production environments:
30+
31+
```javascript
32+
var express = require('express');
33+
34+
// Load .env files (loads .env, .env.[NODE_ENV], and .env.local)
35+
express.loadEnv();
36+
37+
var app = express();
38+
// ... rest of your app
39+
```
40+
41+
### Watch Mode (Development)
42+
43+
Enable automatic reloading when `.env` files change. Perfect for development:
44+
45+
```javascript
46+
var express = require('express');
47+
48+
// Enable watch mode with callbacks
49+
var unwatch = express.loadEnv({
50+
watch: true,
51+
onChange: function(changed, loaded) {
52+
console.log('Environment variables changed:');
53+
Object.keys(changed).forEach(function(key) {
54+
var change = changed[key];
55+
if (change.type === 'added') {
56+
console.log(' + ' + key + ' = ' + change.value);
57+
} else if (change.type === 'modified') {
58+
console.log(' ~ ' + key + ': ' + change.oldValue + ' -> ' + change.newValue);
59+
} else if (change.type === 'removed') {
60+
console.log(' - ' + key + ' (was: ' + change.oldValue + ')');
61+
}
62+
});
63+
},
64+
onError: function(err) {
65+
console.error('Error reloading .env:', err.message);
66+
}
67+
});
68+
69+
// Stop watching when needed (e.g., on shutdown)
70+
process.on('SIGINT', function() {
71+
unwatch();
72+
process.exit();
73+
});
74+
```
75+
76+
## Options
77+
78+
The `loadEnv()` function accepts the following options:
79+
80+
```javascript
81+
// Load from specific file path
82+
express.loadEnv('.env.custom');
83+
84+
// Or pass options object
85+
express.loadEnv({
86+
// Override existing environment variables (default: false)
87+
override: true,
88+
89+
// Specify environment (default: process.env.NODE_ENV)
90+
env: 'production',
91+
92+
// Enable cascading from .env to .env.[env] (default: true)
93+
cascade: true,
94+
95+
// Enable file watching (default: false)
96+
watch: true,
97+
98+
// Callback when variables change (watch mode only)
99+
onChange: function(changed, loaded) {
100+
// changed: object with change details
101+
// loaded: newly loaded environment variables
102+
},
103+
104+
// Callback for errors (watch mode only)
105+
onError: function(err) {
106+
console.error(err);
107+
}
108+
});
109+
110+
// Load only environment-specific file (no cascading)
111+
express.loadEnv({ env: 'production', cascade: false });
112+
```
113+
114+
## File Loading Priority
115+
116+
With default settings, files are loaded in this order (later files override earlier ones):
117+
118+
1. `.env` - Base configuration
119+
2. `.env.[NODE_ENV]` - Environment-specific (e.g., `.env.development`, `.env.production`)
120+
3. `.env.local` - Local overrides (should be in `.gitignore`)
121+
122+
## Example .env File
123+
124+
```bash
125+
# Application settings
126+
APP_NAME=My Express App
127+
APP_ENV=development
128+
PORT=3000
129+
130+
# API Configuration
131+
API_URL=https://api.example.com
132+
API_KEY=your_api_key_here
133+
134+
# Feature flags
135+
DEBUG=true
136+
MAX_ITEMS=100
137+
138+
# Multi-line value
139+
DATABASE_URL="postgresql://user:pass@localhost/db"
140+
```

examples/env-variables/index.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
'use strict'
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
var express = require('../../');
8+
9+
// Load environment variables from .env file
10+
// This should be done BEFORE creating the app
11+
// Automatically loads .env, .env.[NODE_ENV], and .env.local
12+
13+
// Option 1: Simple load (recommended for production)
14+
express.loadEnv();
15+
16+
// Option 2: Load with file watching (useful for development)
17+
// Uncomment below to enable automatic reloading when .env files change
18+
/*
19+
var unwatch = express.loadEnv({
20+
watch: true,
21+
onChange: function(changed, loaded) {
22+
console.log('Environment variables changed:');
23+
Object.keys(changed).forEach(function(key) {
24+
var change = changed[key];
25+
if (change.type === 'added') {
26+
console.log(' + ' + key + ' = ' + change.value);
27+
} else if (change.type === 'modified') {
28+
console.log(' ~ ' + key + ': ' + change.oldValue + ' -> ' + change.newValue);
29+
} else if (change.type === 'removed') {
30+
console.log(' - ' + key + ' (was: ' + change.oldValue + ')');
31+
}
32+
});
33+
},
34+
onError: function(err) {
35+
console.error('Error reloading environment variables:', err.message);
36+
}
37+
});
38+
39+
// To stop watching (e.g., on app shutdown):
40+
// unwatch();
41+
*/
42+
43+
var app = module.exports = express();
44+
var logger = require('morgan');
45+
46+
// custom log format
47+
if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url'))
48+
49+
app.get('/', function(req, res){
50+
var nodeEnv = process.env.NODE_ENV || 'development';
51+
res.send('<h1>Environment Variables Example</h1>'
52+
+ '<p>This example demonstrates how to use Express built-in .env file loading.</p>'
53+
+ '<p><strong>Current Environment:</strong> ' + nodeEnv + '</p>'
54+
+ '<ul>'
55+
+ '<li><a href="/env">View loaded environment variables</a></li>'
56+
+ '<li><a href="/config">View application configuration</a></li>'
57+
+ '</ul>'
58+
+ '<hr>'
59+
+ '<p><strong>Features:</strong></p>'
60+
+ '<ul>'
61+
+ '<li>Automatically loads .env, .env.[NODE_ENV], and .env.local files</li>'
62+
+ '<li>Optional file watching for automatic reloads (see source code)</li>'
63+
+ '<li>Environment-specific configuration</li>'
64+
+ '<li>Cascading values with .env.local overrides</li>'
65+
+ '</ul>'
66+
+ '<hr>'
67+
+ '<p><strong>Try running with different environments:</strong></p>'
68+
+ '<pre>NODE_ENV=development node index.js\nNODE_ENV=production node index.js</pre>'
69+
+ '<p><strong>Enable watch mode:</strong> Uncomment the watch example in index.js and modify your .env file to see live updates!</p>');
70+
});
71+
72+
app.get('/env', function(req, res){
73+
// Display some environment variables
74+
var safeEnvVars = {
75+
APP_NAME: process.env.APP_NAME,
76+
APP_ENV: process.env.APP_ENV,
77+
PORT: process.env.PORT,
78+
DEBUG: process.env.DEBUG,
79+
API_URL: process.env.API_URL,
80+
MAX_ITEMS: process.env.MAX_ITEMS
81+
};
82+
83+
res.send('<h1>Environment Variables</h1>'
84+
+ '<p>The following variables were loaded from .env file:</p>'
85+
+ '<pre>' + JSON.stringify(safeEnvVars, null, 2) + '</pre>'
86+
+ '<p><a href="/">Back to home</a></p>');
87+
});
88+
89+
app.get('/config', function(req, res){
90+
// Use environment variables for configuration
91+
var config = {
92+
appName: process.env.APP_NAME,
93+
environment: process.env.APP_ENV,
94+
port: process.env.PORT || 3000,
95+
debug: process.env.DEBUG === 'true',
96+
apiUrl: process.env.API_URL,
97+
maxItems: parseInt(process.env.MAX_ITEMS) || 10
98+
};
99+
100+
res.send('<h1>Application Configuration</h1>'
101+
+ '<p>Configuration built from environment variables:</p>'
102+
+ '<pre>' + JSON.stringify(config, null, 2) + '</pre>'
103+
+ '<p><a href="/">Back to home</a></p>');
104+
});
105+
106+
/* istanbul ignore next */
107+
if (!module.parent) {
108+
var port = process.env.PORT || 3000;
109+
app.listen(port);
110+
console.log('Express started on port ' + port);
111+
console.log('App Name: ' + (process.env.APP_NAME || 'Not set'));
112+
console.log('Environment: ' + (process.env.APP_ENV || 'Not set'));
113+
}

lib/express.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,9 @@ exports.raw = bodyParser.raw
7979
exports.static = require('serve-static');
8080
exports.text = bodyParser.text
8181
exports.urlencoded = bodyParser.urlencoded
82+
83+
/**
84+
* Expose utilities.
85+
*/
86+
87+
exports.loadEnv = require('./utils').loadEnv;

0 commit comments

Comments
 (0)