Adding custom code

View as Markdown

Fern-generated SDKs are designed to be extended with custom logic, methods, and dependencies. If you want your SDK to do more than just make basic API calls (like combining multiple calls, processing data, adding utilities), you can add custom code that lives in harmony with the generated code.

Fern provides two complementary tools for keeping your customizations safe across regenerations:

  • .fernignore — Full-file ownership. The generator stops touching listed files entirely. Use for fully hand-written modules, READMEs, or custom workflows. Trade-off: you also stop receiving generator updates to those files.
  • Replay — Line-level edits. Keep generated files under generator control, and reapply your edits via 3-way merge on every regeneration.

Full-file ownership with .fernignore

.fernignore applies only to SDK generation. It has no effect on Fern Docs builds.

Use .fernignore to protect files you own end-to-end from being overwritten during SDK regeneration.

Add your custom files to the SDK repository and list them in .fernignore. A .fernignore file is automatically created in your SDK repository when you use GitHub publishing.

Your .fernignore file might look something like this:

.fernignore
1# Documentation and licensing
2README.md
3LICENSE
4
5# Custom workflows
6.github/workflows/test.yml
7.github/workflows/ci.yml
8
9# Custom code
10src/CustomClient.ts

For another real-world example, see Cohere’s .fernignore file for their TypeScript SDK.

You’ll have a separate .fernignore file for each of your SDKs:

company-repo# Top-level repo for all SDKs
fern
typescript-sdk-repo# Repository for a TypeScript SDK
.fernignore
.github
src
python-sdk-repo
.fernignore
.github
src

Line-level edits with Replay

Replay automatically preserves the edits you make to your generated SDK across regenerations. When you commit a change to generated code, Replay scans your repo’s history since the last [fern-generated] commit and stores each customer commit as a tracked patch in .fern/replay.lock. On the next fern generate, those patches are reapplied to the freshly generated SDK via 3-way merge, and the result lands as a [fern-replay] commit on top of [fern-generated] in the regeneration PR:

Regeneration PR
* abc123 (HEAD -> main) [fern-replay] Apply customizations
* 789abc [fern-generated] Update SDK to spec rev 0451
* 234bcd Add helpers on top of User type
* ...

If the generator and your customization changed the same lines, Replay reports the conflict in the PR body. Run fern replay resolve locally to walk through it.

Enable Replay

For SDKs on pull-request output mode, run fern generate to turn Replay on globally. You’ll see that .fern/replay.lock is committed to your SDK repo. From that point on, edits you make to generated files are tracked automatically.

To enable Replay on an SDK that’s currently on release or push mode, switch to pull-request mode via the migration guide.

Disable Replay

To disable Replay, set replay.enabled: false at the top level of generators.yml. See the replay reference.

Customization patterns by language

Each SDK generator has its own conventions for adding custom code: how to extend the generated client, where helpers go, how to declare dependencies. See the guide for your language: