How to Handle Environment Variables in Pi-Web: Configuration Patterns Explained

Pi-Web reads configuration values from the Node.js process environment using process.env, applying nullish coalescing fallbacks for optional settings and throwing explicit errors for required secrets.

Pi-Web is a Next.js-based application that relies on environment variables for runtime configuration, security policies, and external service integration. Understanding how to handle environment variables in pi-web ensures your deployment remains secure, portable, and maintainable across development, staging, and production environments.

Where Pi-Web Accesses Environment Variables

The codebase accesses process.env across several critical modules to configure authentication, security policies, and external API endpoints.

Authentication and Host Security

The authentication layer reads sensitive credentials directly from the environment. In lib/web-auth.ts, the application retrieves the password protection setting:

// lib/web-auth.ts
export const getPassword = (): string => {
  const pwd = process.env.PI_WEB_PASSWORD;
  if (!pwd) {
    throw new Error("Missing required env var PI_WEB_PASSWORD");
  }
  return pwd;
};

Host restrictions are configured in lib/request-security.ts, which builds an allow-list from two environment variables:

// lib/request-security.ts
export const allowedHosts = [
  process.env.PI_WEB_HOSTNAME,
  ...(process.env.PI_WEB_ALLOWED_HOSTS?.split(",") ?? []),
].filter(Boolean);

External API Configuration

The skills integration layer uses SKILLS_API_URL to configure backend communication. In lib/skill-updates.ts and app/api/skills/search/route.ts, the code provides a production-ready fallback:

// lib/skill-updates.ts
const DEFAULT_SKILLS_API_BASE = process.env.SKILLS_API_URL ?? "https://skills.sh";

Build-Time Public Variables

For client-side exposure, Pi-Web uses the NEXT_PUBLIC_ prefix convention. The app/api/app-update/route.ts file exposes the application version to the browser:

// app/api/app-update/route.ts
const version = process.env.NEXT_PUBLIC_APP_VERSION;

Git Operations Environment

When spawning git subprocesses in lib/worktree.ts and lib/git-changes.ts, Pi-Web preserves the parent environment while injecting locale settings for consistent output parsing:

// lib/worktree.ts
await exec("git", ["worktree", "add", /* ... */], {
  env: { ...process.env, LC_ALL: "C" },
});

Configuration Patterns and Implementation

Pi-Web follows consistent patterns for environment variable handling that balance flexibility with reliability.

Validating Required Variables

Critical configuration values trigger immediate failures with descriptive messages rather than silent undefined behavior. The PI_WEB_PASSWORD validation in lib/web-auth.ts demonstrates this defensive approach, ensuring the application never starts in an insecure state.

Providing Sensible Defaults

Optional configuration uses the nullish coalescing operator (??) to supply defaults. This pattern appears in the skills API configuration, where missing values default to the production service URL rather than causing runtime errors.

Parsing Complex Values

Multi-value configuration leverages optional chaining and array spreading. The PI_WEB_ALLOWED_HOSTS variable accepts comma-separated hostnames, which lib/request-security.ts splits and filters to build a clean whitelist array.

Scoped Environment Inheritance

Child processes receive explicitly scoped environments rather than blanket inheritance. The git execution helpers spread process.env only when necessary, then override specific keys like LC_ALL to ensure deterministic command output while maintaining access to user PATH and other essential variables.

Security and Portability Benefits

Handling configuration through environment variables keeps sensitive values like PI_WEB_PASSWORD outside the source tree and version control. This approach enables the same Docker image or deployment artifact to run across different machines, CI pipelines, and cloud providers without code changes.

Feature toggles such as NODE_ENV guard development-only behaviors, as seen in lib/i18n/format.ts where console warnings appear only during development builds. This conditional logic prevents performance overhead and information leakage in production.

Summary

  • Access Pattern: Pi-Web reads variables via process.env throughout lib/web-auth.ts, lib/request-security.ts, and API routes.
  • Validation Strategy: Required variables throw explicit errors during startup; optional variables use nullish coalescing (??) for defaults.
  • Security Practice: Sensitive values remain out of source code, while public values use the NEXT_PUBLIC_ prefix for browser exposure.
  • Subprocess Handling: Git commands in lib/worktree.ts inherit the parent environment selectively using { ...process.env, LC_ALL: "C" }.
  • Configuration Format: Comma-separated lists in PI_WEB_ALLOWED_HOSTS are parsed into arrays for host whitelist validation.

Frequently Asked Questions

What happens if PI_WEB_PASSWORD is not configured?

The application throws a clear startup error. In lib/web-auth.ts, the code explicitly checks for the variable's presence and throws new Error("Missing required env var PI_WEB_PASSWORD") if undefined, preventing the server from running in an unprotected state.

How do I allow multiple hostnames in pi-web?

Set the PI_WEB_ALLOWED_HOSTS environment variable to a comma-separated list of domains. The lib/request-security.ts module splits this string using ?.split(",") and combines it with PI_WEB_HOSTNAME to build the complete whitelist.

How are environment variables exposed to the browser?

Only variables prefixed with NEXT_PUBLIC_ are sent to the client. For example, NEXT_PUBLIC_APP_VERSION is accessed in app/api/app-update/route.ts to communicate build information to the frontend, while secrets like PI_WEB_PASSWORD remain server-side only.

Why does pi-web spread process.env when running git commands?

The spread operator in lib/worktree.ts (env: { ...process.env, LC_ALL: "C" }) preserves the user's PATH and other essential environment variables while overriding the locale to ensure consistent, parseable git output across different system configurations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →