
# Validation & Schema Generation

Two functions cover the offline half of the API: check a config without starting anything, and emit the JSON Schema that describes every config.

## `validateConfig(config)`

Decode an unknown value against `AppSchema`. It never throws — a bad config comes back as data, so you can report several problems at once instead of dying on the first.

```typescript
import { validateConfig } from 'sovrium'

const result = validateConfig({ name: 'My App' })

if (result.valid) {
  console.log(result.config.name)
} else {
  result.errors.forEach((error) => console.error(error))
}
```

### `ValidateConfigResult`

The result is a **discriminated union**, not a record with optional fields. Narrow on `valid` before reading anything else — TypeScript will not let you do otherwise.

| When           | Shape                                         |
| -------------- | --------------------------------------------- |
| `valid: true`  | `{ valid: true, config: AppConfig }`          |
| `valid: false` | `{ valid: false, errors: readonly string[] }` |

`errors` holds **strings**, one per line of the formatted decode tree — each naming the path that failed and why. On the success branch there is no `errors` property at all, and on the failure branch there is no `config`.

```typescript
import { validateConfig } from 'sovrium'

const untrusted: unknown = JSON.parse(await Bun.file('app.json').text())
const result = validateConfig(untrusted)

if (!result.valid) {
  console.error(`Invalid config:\n${result.errors.join('\n')}`)
  process.exit(1)
}

// `result.config` is an AppConfig here, and only here.
console.log(`Validated ${result.config.name}`)
```

:::callout
**Looser than `sovrium validate`.** `validateConfig` runs the same `AppSchema` the server boots from, so required properties, enum members and shape errors are all caught. Two things it does **not** do: it tolerates unrecognised extra properties (the CLI rejects them), and it skips the unknown-field-type sweep. Treat it as the in-process guard and [`sovrium validate`](/en/docs/config-validation) as the pre-deploy gate.
:::

## `generateAppJsonSchema()`

Produce the JSON Schema (Draft-07) for the app configuration as a plain object — the same document `sovrium schema` prints.

```typescript
import { generateAppJsonSchema } from 'sovrium'

const schema = generateAppJsonSchema()

await Bun.write('app.schema.json', JSON.stringify(schema, null, 2))
```

It takes no arguments and reads nothing from the environment: the schema is derived from `AppSchema` itself, so the output depends only on the Sovrium version. That makes it safe to regenerate in CI and diff — a change in the file is a change in the schema, never in the machine that ran it.

A common use is pinning the schema alongside the config so editors validate against the exact version you deploy:

```typescript
// scripts/sync-schema.ts — run after every Sovrium upgrade
import { generateAppJsonSchema } from 'sovrium'

await Bun.write('app.schema.json', JSON.stringify(generateAppJsonSchema(), null, 2))
```

```yaml
# app.yaml
# yaml-language-server: $schema=./app.schema.json
name: my-app
```

## Related Pages

- [TypeScript API Overview](/en/docs/typescript) — `AppConfig` and the other functions.
- [Validating a Config](/en/docs/config-validation) — the CLI checker and its extra sweeps.
- [JSON Schema](/en/docs/json-schema) — the hosted schema URLs.
- [Editor Setup](/en/docs/json-schema-editors) — pointing VS Code or JetBrains at it.
