---
title: "Config and lockfile"
description: "apiweld.config.ts says which endpoints you want. apiweld.lock.json records exactly what was built. Commit both."
---

> Documentation Index
> Fetch the complete documentation index at: https://apiweld.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Config and lockfile

Apiweld keeps a project's state in two files, both committed:

- **`apiweld.config.ts`** says what you want: which APIs, which endpoints, and how to generate them. You (or your agent) edit it.
- **`apiweld.lock.json`** records what was actually built: the exact spec, the endpoints, and the tool versions. Apiweld writes it. Don't edit it by hand.

This works like `package.json` and a package-manager lockfile. The config states intent, and the lock makes every build reproducible.

## Config

```ts title="apiweld.config.ts"
import { defineConfig } from "apiweld";

export default defineConfig({
  output: "src/apis",
  generator: {
name: "hey-api",
client: "fetch",
validators: "zod",
  },
  verify: {
test: "bun run test",
  },
  apis: {
stripe: {
  source: "https://raw.githubusercontent.com/stripe/openapi/master/latest/openapi.spec3.json",
  operations: [
    "POST /v1/refunds",
    "GET /v1/refunds/{refund}",
  ],
  policy: { autoRegenerate: "safe" },
},
github: {
  source: "apisguru:github.com",
  operations: ["GET /repos/{owner}/{repo}/pulls"],
},
  },
});
```

The file is TypeScript, so your editor type-checks and autocompletes it, and it can hold functions such as [patches](#fix-a-broken-spec). There's no build step: Apiweld loads it directly.

After the first `generate`, Apiweld writes `apiweld-env.d.ts`, which gives you autocomplete for the operations of every API already in the lock.

### Top-level options

| Option | Default | Meaning |
| --- | --- | --- |
| `output` | `"src/apis"` | Where generated clients go, relative to the config file. Each API gets its own folder, named after its key. |
| `generator.name` | `"hey-api"` | `"hey-api"` generates TypeScript with [Hey API](https://heyapi.dev). `"oapi-codegen"` generates Go. |
| `generator.client` | `"fetch"` | The HTTP client for Hey API: `fetch`, `axios`, `ky`, `ofetch`, `next`, `nuxt`, or any other client Hey API supports. |
| `generator.validators` | off | `"zod"` generates Zod schemas and enables the [runtime drift log](/drift#runtime-drift). |
| `generator.options` | — | Extra options passed through to the generator. |
| `verify.test` | — | A command for `apiweld verify` to run after its type-check, such as `"bun run test"`. |

### Per-API options

Each key under `apis` becomes a folder under `output` and the name you import from.

| Option | Meaning |
| --- | --- |
| `source` | Where the spec comes from. See [Sources](#sources). |
| `operations` | The endpoints to generate, as `METHOD /path`. `add` and `remove` keep this list up to date. |
| `policy.autoRegenerate` | `"safe"` lets `apiweld update` regenerate by itself when every change is safe. `"never"` always waits for you. Breaking changes are never applied automatically. |
| `levelOverrides` | Re-labels specific change types for this API, for example `{ "response-optional-property-removed": "risky" }`. Useful when a provider's habits make one rule noisy. |
| `allowRemoteHosts` | Other hosts the spec may load `$ref`s from. By default, only the spec's own host is allowed. |
| `patch` | Functions that fix a broken spec before generation. See [below](#fix-a-broken-spec). |

### Sources

| Source | Where the spec comes from |
| --- | --- |
| `https://…` | That URL. GitHub `blob` links are fetched as the raw file. |
| `file:<path>` | A spec on disk. Use this for private or internal APIs. |
| `apisguru:<id>` | The [APIs.guru](https://apis.guru) directory entry. When the entry records the provider's original URL (`x-origin`), Apiweld fetches from the provider directly, so you see changes as soon as they're published. |
| `wellknown:<domain>` | The API catalog the provider publishes at `https://<domain>/.well-known/api-catalog` ([RFC 9727](https://www.rfc-editor.org/rfc/rfc9727)). |

### Fix a broken spec

Some upstream specs have mistakes that break generation. Add a `patch` to that API to fix them. The functions go to Hey API's [`parser.patch`](https://heyapi.dev/openapi-ts/configuration/parser#patch).

```ts
github: {
  source: "apisguru:github.com",
  operations: ["GET /repos/{owner}/{repo}/pulls"],
  patch: {
schemas: {
  "pull-request-simple": (schema) => {
    // fix the schema, then return it
    return schema;
  },
},
  },
},
```

Patches are code you wrote in your own config. Apiweld never runs code that comes from a spec.

### How add and remove edit the file

`apiweld add` and `remove` (and the matching MCP tools) edit `apiweld.config.ts` in place and keep your formatting, comments, and functions. If the config is built dynamically and can't be edited safely, Apiweld prints the snippet to paste in instead of rewriting the file.

## Lockfile

```json title="apiweld.lock.json"
{
  "lockVersion": 1,
  "apis": {
"stripe": {
  "resolvedUrl": "https://raw.githubusercontent.com/stripe/openapi/master/latest/openapi.spec3.json",
  "specHash": "sha256:9f2c…e41a",
  "specVersion": "2026-08-27",
  "fetchedAt": "2026-09-23T07:40:12Z",
  "etag": "W/\"5d1f…\"",
  "operations": ["GET /v1/refunds/{refund}", "POST /v1/refunds"],
  "sliceHash": "sha256:1b7a…03cd",
  "schemas": 14,
  "generator": "@hey-api/openapi-ts@<version>",
  "engine": "apiweld-engine@<version> (oasdiff <version>)",
  "outputHash": "sha256:c08e…77b2"
}
  }
}
```

Keys and operations are sorted, so a change to the lock always means something actually changed, not just the ordering.

The lock has three hashes, and each one answers a different question:

| Hash | What it covers | When it changes |
| --- | --- | --- |
| `specHash` | The whole upstream spec | The provider changed anything. Apiweld then compares `sliceHash` to see whether it matters to you. |
| `sliceHash` | Only your endpoints and the schemas they use | Something you use changed. This is the only hash that triggers a drift report. |
| `outputHash` | The generated files | Someone edited the generated code by hand. Apiweld warns you, because the next `generate` will overwrite the edit. |

The other fields: `resolvedUrl` is the URL that was actually fetched. `etag` lets the next check skip the download when nothing changed. `generator` and `engine` record the tool versions, so a rebuild produces the same output.

## Files in your project

```text
apiweld.config.ts
apiweld.lock.json
apiweld-env.d.ts          # operation autocomplete for the config
src/apis/
  stripe/                 # generated: read it, don't edit it
sdk.gen.ts
types.gen.ts
zod.gen.ts
index.ts
  github/
.apiweld/                 # gitignored
  reports/                # drift reports and heal plans, JSON and Markdown
  drift.log.jsonl         # runtime drift log (shapes only, never values)
```

Commit the generated clients. That way reviewers see every change, agents can read the code, and CI doesn't need the network to build.

## Machine settings

Apiweld also keeps a cache that all your projects share:

```text
~/.apiweld/
  settings.json           # optional, see below
  catalog.db              # the search index
  specs/
9f2c…e41a.json        # every spec version fetched, named by its hash
  http-cache.json         # ETags, so unchanged specs aren't downloaded again
```

Old spec versions stay in `specs/`, so Apiweld can diff against the version in your lock and rebuild it offline even after the provider has moved on.

`settings.json` is optional:

```json title="~/.apiweld/settings.json"
{
  "offline": false,
  "proxy": "http://proxy.internal:3128",
  "catalogs": [
{ "name": "internal", "path": "/srv/specs" },
{ "name": "partners", "urls": ["https://partner.example.com/openapi.json"] }
  ]
}
```

`catalogs` adds your own specs to search, next to the public ones. Each result is labelled with the catalog it came from.

Source: https://apiweld.dev/config/index.mdx
