# How Openship Handles Configuration for Its Packages: The openship.json Architecture

> Learn how openship handles package configuration using the openship.json file. Discover its architecture for merging defaults, overrides, and environment variables into unified runtime settings.

- Repository: [oblien/openship](https://github.com/oblien/openship)
- Tags: architecture
- Published: 2026-07-23

---

**Openship centralizes package-level configuration in a declarative, strongly-typed [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) file that merges auto-detected defaults, explicit overrides, and environment variables into a unified runtime configuration.**

The `oblien/openship` repository implements a layered configuration system designed to support both simple applications and complex monorepos. By combining static schema validation with intelligent runtime detection, the system provides type-safe settings while remaining flexible enough to handle encrypted secrets and per-service customizations.

## The Declarative openship.json File

All configuration originates from an [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) file located at the repository root. This file follows a strict schema defined in [`packages/core/src/openship-config/schema.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/openship-config/schema.ts), which enforces type safety and validates structure before the runtime consumes any values. The schema supports framework detection, service definitions, domain mappings, and monorepo-specific overrides.

## Validation and Parsing

When the CLI or web UI initializes, [`packages/core/src/openship-config/parse.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/openship-config/parse.ts) processes the raw JSON. This module validates the file against the schema and coerces values into a fully-typed `OpenshipConfig` object, preventing malformed configurations from reaching production.

## Runtime Configuration Layer

The [`packages/core/src/runtime-config.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/runtime-config.ts) module exposes the `getConfig()` helper that packages import to access settings. As implemented in `oblien/openship`, this utility merges three distinct configuration sources in strict order of precedence:

1. **Auto-detected defaults** – The system inspects the codebase via [`packages/core/src/stacks.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/stacks.ts) to identify frameworks (such as Next.js), Dockerfiles, and build commands, generating baseline settings automatically.

2. **[`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) overrides** – Any field defined in the root configuration file replaces the auto-detected value, while omitted fields retain their intelligent defaults.

3. **Environment variables** – Values supplied via `process.env` or encrypted secret objects temporarily override the merged configuration for specific deployment runs.

Packages access the final merged configuration through the `@openship/core` import:

```typescript
import { getConfig } from "@openship/core/runtime-config";

const cfg = getConfig();
console.log(cfg.port);           // 3000 or auto-detected fallback
console.log(cfg.services?.[0]);  // Service-specific configuration

```

## Persistent Settings and Secret Management

Configuration requiring persistence across restarts—including SSH server details, SMTP credentials, and resource limits—stores in the internal database. The schema defined in [`packages/db/src/schema/settings.ts`](https://github.com/oblien/openship/blob/main/packages/db/src/schema/settings.ts) manages these values, with sensitive fields stored as encrypted JSON blobs. This approach ensures secrets remain secure at rest while remaining accessible to the runtime configuration layer.

```typescript
await db
  .updateTable("settings")
  .set({ smtpPassword: { value: "s3cr3t", secret: true } })
  .where("id", "=", 1)
  .run();

```

## Monorepo Support with Per-App Overrides

For monorepo structures, the schema includes an `openshipMonorepoApp` definition allowing each sub-application to specify independent build commands, ports, and frameworks. These per-app overrides apply after the global detection step, enabling independent build and deployment workflows while maintaining a common configuration surface across the repository.

A minimal [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) configuration for a Next.js application appears as:

```json
{
  "framework": "next",
  "port": 3000,
  "services": [
    { "name": "web", "build": "npm run build", "env": { "NODE_ENV": "production" } }
  ],
  "domains": [{ "domain": "app.example.com" }]
}

```

## Summary

- **Openship** uses a root-level [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) file as the primary configuration source, validated against a TypeScript schema in [`packages/core/src/openship-config/schema.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/openship-config/schema.ts).
- The parsing layer in [`packages/core/src/openship-config/parse.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/openship-config/parse.ts) converts raw JSON into typed `OpenshipConfig` objects.
- Runtime configuration merges auto-detected defaults, file-based overrides, and environment variables via the `getConfig()` helper in [`packages/core/src/runtime-config.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/runtime-config.ts).
- Persistent settings and encrypted secrets store in database tables defined by [`packages/db/src/schema/settings.ts`](https://github.com/oblien/openship/blob/main/packages/db/src/schema/settings.ts).
- Monorepo support allows sub-applications to define independent configurations through the `openshipMonorepoApp` schema property.

## Frequently Asked Questions

### What file format does Openship use for package configuration?

Openship uses a JSON file named [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) located at the repository root. This file follows a strictly typed schema defined in [`packages/core/src/openship-config/schema.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/openship-config/schema.ts), supporting values for frameworks, ports, services, domains, and monorepo-specific settings.

### How does Openship handle sensitive configuration values like passwords?

Sensitive values persist in the internal database using the schema defined in [`packages/db/src/schema/settings.ts`](https://github.com/oblien/openship/blob/main/packages/db/src/schema/settings.ts). These fields store as encrypted JSON blobs marked with `"secret": true`, ensuring credentials like SMTP passwords or SSH keys remain encrypted at rest while remaining accessible to the runtime configuration system.

### Can environment variables override openship.json settings?

Yes. The runtime configuration layer applies environment variables as the highest precedence layer after auto-detected defaults and [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) values. You can temporarily override any configuration field for a specific run by setting the corresponding environment variable before starting the CLI or web UI.

### How does Openship support configuration in monorepos?

The [`openship.json`](https://github.com/oblien/openship/blob/main/openship.json) schema includes an `openshipMonorepoApp` definition that allows each sub-application to provide its own build commands, ports, and framework settings. These per-app configurations apply after global auto-detection, enabling independent deployment pipelines while sharing the centralized configuration system.