How to Read Environment Variables from Bnlang
Environment variables are key-value pairs the operating system makes available to a process. They're the standard way to pass configuration (ports, database URLs, secrets) without baking values into the code.
The built-in sys module exposes them; the dotenv library layers a .env file on top for local development.
Reading One Variable
sys.env(name) returns the value as a string, or null if the variable isn't set. Pair it with a default.
import "sys" as sys;
var user = sys.env("USER");
if (user == null) { user = "Guest"; }
print("Current user:", user);
USER=Alice bnl env.bnl
# Output: Current user: Alice
Reading Multiple Variables
import "sys" as sys;
var host = sys.env("HOST"); if (host == null) { host = "localhost"; }
var port = sys.env("PORT"); if (port == null) { port = "3000"; }
print("Server will run at http://" + host + ":" + port);
HOST=127.0.0.1 PORT=8080 bnl config.bnl
# Output: Server will run at http://127.0.0.1:8080
Dumping the Whole Environment
import "sys" as sys;
var all = sys.envs(); // map of every env var
for (var k of all.keys()) {
print(k, "=", all[k]);
}
Local .env Files with the dotenv Library
For local development you usually don't want to export each variable in the shell. The dotenv library parses a .env file into a map you can read from.
# .env
DATABASE_URL=postgres://localhost/myapp
API_KEY=dev-secret
import "dotenv" as dotenv;
var env = dotenv.load_or_empty(".env");
print(env.DATABASE_URL);
print(env.API_KEY);
Best Practices
- Always provide a sensible default for every variable you read.
- Keep
.envout of version control — commit a.env.exampletemplate instead. - Don't log secrets. Treat
API_KEY/*_TOKEN/*_SECRETas sensitive. - For multi-environment apps, layer
.env.localover.envand let real OS environment variables win at the top.