The environment object provides access to environment variables in your Zuplo
API gateway. It returns a record of environment variable names to their values.
Access environment variables using the environment object:
Code
import { environment, ZuploContext, ZuploRequest } from "@zuplo/runtime";export default async function handler( request: ZuploRequest, context: ZuploContext,) { // Access environment variables const apiKey = environment.API_KEY; const apiUrl = environment.API_BASE_URL; if (!apiKey) { throw new Error("API_KEY environment variable is not set"); } const response = await fetch(`${apiUrl}/data`, { headers: { Authorization: `Bearer ${apiKey}`, }, }); return response;}
Type Safety
Since environment variables might not be defined, they return
string | undefined:
Code
import { environment } from "@zuplo/runtime";// TypeScript knows this could be undefinedconst value = environment.MY_VAR; // string | undefined// Always check before usingif (value) { // value is string here console.log(value.toUpperCase());}// Or provide a defaultconst port = environment.PORT || "3000";
Common Patterns
Required Environment Variables
Create a helper to validate required variables:
Code
import { environment, ConfigurationError } from "@zuplo/runtime";function getRequiredEnv(name: string): string { const value = environment[name]; if (!value) { throw new ConfigurationError( `Required environment variable '${name}' is not set`, ); } return value;}// Usageexport default async function handler( request: ZuploRequest, context: ZuploContext,) { const apiKey = getRequiredEnv("API_KEY"); const apiUrl = getRequiredEnv("API_BASE_URL"); // Both are guaranteed to be strings return fetch(`${apiUrl}/endpoint`, { headers: { "X-API-Key": apiKey }, });}
Configuration Object
Create a configuration object from environment variables:
To handle environment-specific logic, use environment variables that you define:
Code
import { environment } from "@zuplo/runtime";// Define your own environment variable to identify the environmentconst isProduction = environment.ENVIRONMENT === "production";const isStaging = environment.ENVIRONMENT === "staging";const isDevelopment = environment.ENVIRONMENT === "development";export default async function handler( request: ZuploRequest, context: ZuploContext,) { // Use different endpoints based on environment const apiUrl = isProduction ? "https://api.example.com" : isStaging ? "https://staging-api.example.com" : "https://dev-api.example.com"; // Enable debug logging in non-production if (!isProduction) { context.log.debug("Incoming request", { headers: Object.fromEntries(request.headers), url: request.url, }); } // Use stricter security in production const headers: HeadersInit = { "Content-Type": "application/json", }; if (isProduction) { headers["Strict-Transport-Security"] = "max-age=31536000"; } return new Response("OK", { headers });}
Secret Management
Code
import { environment } from "@zuplo/runtime";// Group related secretsconst secrets = { database: { host: environment.DB_HOST || "localhost", port: environment.DB_PORT || "5432", user: environment.DB_USER, password: environment.DB_PASSWORD, name: environment.DB_NAME || "myapp", }, redis: { url: environment.REDIS_URL || "redis://localhost:6379", }, external: { stripeKey: environment.STRIPE_SECRET_KEY, sendgridKey: environment.SENDGRID_API_KEY, },};// Validate all required secrets on startupfunction validateSecrets() { const missing: string[] = []; if (!secrets.database.user) missing.push("DB_USER"); if (!secrets.database.password) missing.push("DB_PASSWORD"); if (!secrets.external.stripeKey) missing.push("STRIPE_SECRET_KEY"); if (missing.length > 0) { throw new ConfigurationError( `Missing required secrets: ${missing.join(", ")}`, ); }}// Run validationvalidateSecrets();
Environment Detection
Zuplo does not provide a built-in NODE_ENV variable since it runs on a custom
V8 runtime, not Node.js. To implement environment-specific logic, define your
own environment variables (e.g., ENVIRONMENT, STAGE, or ENV_TYPE) and set
them appropriately for each environment in your project settings.
Best Practices
1. Use Descriptive Names
Code
// Goodenvironment.STRIPE_WEBHOOK_SECRET;environment.DATABASE_CONNECTION_STRING;environment.SLACK_WEBHOOK_URL;// Less clearenvironment.KEY;environment.URL;environment.SECRET;
// Validate at module load time, not request timeconst apiKey = environment.API_KEY;if (!apiKey) { throw new ConfigurationError("API_KEY must be set");}export default async function handler( request: ZuploRequest, context: ZuploContext,) { // apiKey is guaranteed to exist here return fetch("https://api.example.com", { headers: { "X-API-Key": apiKey }, });}
4. Don't Log Secrets
Code
// DON'T do thiscontext.log.info("Config loaded", { apiKey: environment.API_KEY,});// DO this insteadcontext.log.info("Config loaded", { apiKeyPresent: !!environment.API_KEY, apiKeyLength: environment.API_KEY?.length,});
Setting Environment Variables
Environment variables are set in the Zuplo Portal:
Navigate to your project
Go to Settings → Environment Variables
Add variables for each environment (production, preview, development)