# How OpenWork Handles Configuration: Environment Files, Zod Validation, and Desktop Bootstrap

> OpenWork centralizes configuration using environment files, Zod validation, and IPC for type-safe services. Learn how OpenWork manages its configuration pipeline.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: how-to-guide
- Published: 2026-08-07

---

**OpenWork centralizes runtime configuration through a layered pipeline that loads `.env.dev` files via `dotenv`, validates values using Zod schemas, and propagates typed configuration objects through IPC channels to ensure type safety across services.**

OpenWork, the open-source AI workspace platform developed by the `different-ai/openwork` repository, implements a robust configuration management architecture that separates environment secrets from application logic. The system combines file-based environment variables with runtime validation to create strongly-typed configuration objects used by both server-side services and the desktop client. This design ensures consistent configuration interfaces across local development, Docker deployments, and cloud-based installations.

## Environment File Structure and the dotenv Loader

OpenWork stores configurable values in **`.env.dev`** at the repository root, which serves as a template containing defaults and placeholders for secrets. This file acts as the single source of truth for local development defaults.

Every server-side entry point imports the **`dotenv`** package and invokes `dotenv.config()` before any business logic executes. The repository standardizes this pattern across multiple services:

- **Inference service**: [`packages/ee/apps/inference/src/load-env.ts`](https://github.com/different-ai/openwork/blob/main/packages/ee/apps/inference/src/load-env.ts)
- **Den worker proxy**: [`packages/ee/apps/den-worker-proxy/src/load-env.ts`](https://github.com/different-ai/openwork/blob/main/packages/ee/apps/den-worker-proxy/src/load-env.ts)
- **Den gateway**: [`packages/ee/apps/den-gateway/src/load-env.ts`](https://github.com/different-ai/openwork/blob/main/packages/ee/apps/den-gateway/src/load-env.ts)

All three files implement identical loading logic:

```typescript
import dotenv from "dotenv";

const filePath = process.env["OPENWORK_ENV_PATH"] ?? ".env.dev";
dotenv.config({ path: filePath, override: false });

```

The `override: false` option ensures that existing environment variables (such as those injected by Docker or CI pipelines) take precedence over values defined in the `.env` file.

## Type-Safe Validation with Zod Schemas

Rather than accessing raw `process.env` values throughout the codebase, OpenWork validates and parses environment variables into strongly-typed configuration objects using **Zod** schemas.

Each module defines a schema that coerces and validates inputs:

```typescript
import { z } from "zod";

const ConfigSchema = z.object({
  PORT: z.coerce.number().default(3000),
  OPENAI_API_KEY: z.string().min(1),
});

export type Config = z.infer<typeof ConfigSchema>;
export const config: Config = ConfigSchema.parse(process.env);

```

The **install-config** package ([`packages/install-config/src/index.ts`](https://github.com/different-ai/openwork/blob/main/packages/install-config/src/index.ts)) constructs URLs and tokens using this pattern, exposing a `DesktopBootstrapConfig`-style object that the desktop client consumes during initialization.

## Desktop Bootstrap and IPC Propagation

When the desktop client starts, it performs a **bootstrap step** that reads the parsed configuration and persists it for subsequent launches. This ensures that the UI, agents, and MCP (Model Control Plane) share a single source of truth across application restarts.

The IPC layer defines this contract in [`packages/types/src/desktop-ipc.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/desktop-ipc.ts), where the bootstrap command expects a `Partial<DesktopBootstrapConfig>`:

```typescript
args: [config: Partial<DesktopBootstrapConfig>]

```

The desktop application receives this configuration via the IPC channel and stores it locally, allowing offline operation while maintaining connection parameters to remote services.

## Remote Configuration Provisioning

For cloud-based installations, OpenWork supports dynamic configuration provisioning through the **`/v1/install-config`** endpoint. The client constructs the request URL using an installation token supplied in the environment variables.

The logic in [`packages/install-config/src/index.ts`](https://github.com/different-ai/openwork/blob/main/packages/install-config/src/index.ts) demonstrates this pattern:

```typescript
import { URL } from "url";

function configUrlFromInstallLink(input: URL) {
  const token = input.searchParams.get("token");
  if (!token) throw new Error("Missing token");
  
  const protocol = input.protocol.replace(":", "");
  const hostname = input.hostname;
  const url = new URL(
    `/v1/install-config?token=${encodeURIComponent(token)}`,
    `${protocol}://${hostname}`
  );
  return url.toString();
}

```

This approach allows IT administrators to distribute installation links that automatically configure the desktop client without hard-coding secrets or endpoint URLs.

## Runtime Override Behavior

OpenWork's configuration system respects **runtime precedence** through the `dotenv` loader's `override: false` setting. When services start, they first check for existing environment variables before loading the `.env` file.

This hierarchy enables flexible deployment strategies:

1. **Docker/CI injected values** take highest precedence
2. **`.env.dev` or custom env file** provides defaults
3. **Zod schema defaults** apply when variables are missing

This layering allows production containers to override development defaults without modifying source files, while maintaining type safety through Zod's validation layer.

## Summary

- OpenWork uses **`.env.dev`** as the canonical environment template for local development.
- **Three standardized loaders** (`inference`, `den-worker-proxy`, `den-gateway`) invoke `dotenv.config({ path: filePath, override: false })` to populate `process.env`.
- **Zod schemas** validate and coerce environment variables into typed configuration objects, preventing runtime errors from invalid inputs.
- The **desktop bootstrap process** persists configuration via IPC using the `DesktopBootstrapConfig` interface defined in [`packages/types/src/desktop-ipc.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/desktop-ipc.ts).
- Remote provisioning occurs through the **`/v1/install-config`** endpoint, enabling dynamic configuration without hard-coded secrets.
- **Runtime overrides** use the `override: false` parameter to ensure Docker and CI environment variables take precedence over file-based defaults.

## Frequently Asked Questions

### Where does OpenWork store its environment variables?

OpenWork stores environment variables in **`.env.dev`** at the repository root, which serves as a template containing defaults and secret placeholders. For production, the system generates a `.env` file or relies on environment variables injected by the deployment platform. The `dotenv` loader in files like [`packages/ee/apps/inference/src/load-env.ts`](https://github.com/different-ai/openwork/blob/main/packages/ee/apps/inference/src/load-env.ts) reads these values at runtime.

### How does OpenWork ensure configuration values are type-safe?

OpenWork uses **Zod schemas** to validate and parse environment variables before they reach application logic. Each module defines a schema (e.g., `ConfigSchema`) that coerces strings to numbers, validates API keys, and applies defaults. This process transforms raw `process.env` strings into strongly-typed TypeScript objects, catching configuration errors during startup rather than at runtime.

### Can OpenWork fetch configuration from a remote server?

Yes. OpenWork supports remote configuration through the **`/v1/install-config`** endpoint. When users provide an installation URL containing a token, the desktop client fetches configuration parameters from this endpoint. The logic in [`packages/install-config/src/index.ts`](https://github.com/different-ai/openwork/blob/main/packages/install-config/src/index.ts) constructs the request URL and parses the response, enabling centralized configuration management for enterprise deployments without distributing secrets in installer packages.

### How does configuration flow from environment files to the desktop application?

The configuration flows through a **four-stage pipeline**: First, `dotenv.config()` loads values from `.env.dev` into `process.env`. Second, Zod schemas validate and parse these values into typed objects. Third, the desktop bootstrap process receives a `Partial<DesktopBootstrapConfig>` via IPC and persists it locally. Finally, the persisted configuration serves as the single source of truth for the UI and background services across application restarts.