# TypeScript configuration

> Configure TypeScript SDK generation with Fern. Customize namespaces, enable serde layer, manage dependencies, and control file output.

You can customize the behavior of the TypeScript SDK generator in `generators.yml`:

```yml {6-9} title="generators.yml"
groups:
  ts-sdk:
    generators:
      - name: fernapi/fern-typescript-sdk
        version: 3.46.3
        config:
          namespaceExport: AcmePayments
          noSerdeLayer: false
          generateSubpackageExports: true
```

<ParamField path="allowExtraFields" type="boolean" toc={true}>
  Allow fields that are not defined in object schemas. This only applies to serde.

  See [TypeScript serde layer](/sdks/generators/typescript/serde-layer) for more information.
</ParamField>

<ParamField path="defaultTimeoutInSeconds" type="number | 'infinity'" toc={true}>
  The default timeout for network requests. In the generated client, this can be overridden at the request level.
</ParamField>

<ParamField path="enableInlineTypes" type="boolean" default="true" toc={true}>
  When enabled, the inline schemas will be generated as nested types in TypeScript.
  This results in cleaner type names and a more intuitive developer experience.

  `enableInlineTypes: false`:

  ```typescript
  // MyRootType.ts
  import * as MySdk from "...";

  export interface MyRootType {
    foo: MySdk.MyRootTypeFoo;
  }

  // MyRootTypeFoo.ts
  import * as MySdk from "...";

  export interface MyRootTypeFoo {
    bar: MySdk.MyRootTypeFooBar;
  }

  // MyRootTypeFooBar.ts
  import * as MySdk from "...";

  export interface MyRootTypeFooBar {}
  ```

  `enableInlineTypes: true`:

  ```typescript
  // MyRootType.ts
  import * as MySdk from "...";

  export interface MyRootType {
    foo: MyRootType.Foo;
  }

  export namespace MyRootType {
    export interface Foo {
      bar: Foo.Bar;
    }

    export namespace Foo {
      export interface Bar {}
    }
  }
  ```

  Now users can get the deep nested `Bar` type as follows:

  ```typescript
  import { MyRootType } from MySdk;

  const bar: MyRootType.Foo.Bar = {};
  ```
</ParamField>

<ParamField path="extraDependencies" type="object" default="{}" toc={true}>
  <Warning title="Pro and Enterprise feature">
    This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com).
  </Warning>

  Specify extra dependencies in the generated `package.json`. This is useful
  when you add custom code to your SDK that requires additional dependencies.

  ```yaml
  # generators.yml
  config:
    extraDependencies:
      lodash: "3.0.2"
  ```
</ParamField>

<ParamField path="extraDevDependencies" type="object" default="{}" toc={true}>
  <Warning title="Pro and Enterprise feature">
    This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com).
  </Warning>

  Specify extra dev dependencies in the generated `package.json`.

  ```yaml
  # generators.yml
  config:
    extraDevDependencies:
      jest: "29.0.7"
  ```

  <Note>
    Only applies when publishing to Github.
  </Note>
</ParamField>

<ParamField path="extraPeerDependencies" type="object" toc={true}>
  Specify extra peer dependencies in the generated `package.json`:

  ```yaml
  # generators.yml
  config:
    extraPeerDependencies:
      react: ">=16.8.0 <19.0.0"
      "react-dom": ">=16.8.0 <19.0.0"
  ```
</ParamField>

<ParamField path="extraPeerDependenciesMeta" type="object" toc={true}>
  Specify extra peer dependencies meta fields in the generated `package.json`:

  ```yaml
  # generators.yml
  config:
    extraPeerDependencies:
      react: ">=16.8.0 <19.0.0"
      "react-dom": ">=16.8.0 <19.0.0"
  ```
</ParamField>

<ParamField path="fetchSupport" type="'node-fetch' | 'native'" toc={true}>
  Choose whether you want to include `node-fetch` to support Node.js versions before Node.js 18, or choose `native` to use the native `fetch` API available in Node.js 18 and later.
</ParamField>

<ParamField path="fileResponseType" type="'stream' | 'binary-response'" toc={true}>
  Change the type of response returned to the user for a binary HTTP response:

  * `stream`: Returns a stream. See `streamType`, which controls the type of stream returned.
  * `binary-response`: Returns the `BinaryResponse` type, which allows the user to choose how to consume the binary HTTP response.
    Here's how your users can interact with the `BinaryResponse`:

  ```typescript
  const response = await client.getFile(...);
  const stream = response.stream();
  // const arrayBuffer = await response.arrayBuffer();
  // const blob = await response.blob();
  // const bytes = await response.bytes();
  const bodyUsed = response.bodyUsed;
  ```
</ParamField>

<ParamField path="formDataSupport" type="'Node16' | 'Node18'" toc={true}>
  Choose whether you want to support Node.js 16 and above (`Node16`), or Node.js 18 and above (`Node18`).

  * `Node16` uses multiple dependencies to support multipart forms, including `form-data`, `formdata-node`, and `form-data-encoder`.
  * `Node18` uses the native FormData API, and accepts a wider range of types for file uploads, such as `Buffer`, `File`, `Blob`, `Readable`, `ReadableStream`, `ArrayBuffer`, and `Uint8Array`
</ParamField>

<ParamField path="generateWireTests" type="boolean" default="true" toc={true}>
  Generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected.
</ParamField>

<ParamField path="generateSubpackageExports" type="boolean" default="false" toc={true}>
  Generates subpackage exports that allow users to import individual clients directly, rather than importing the entire SDK. This enables JavaScript bundlers to tree-shake unused code, significantly reducing bundle sizes.

  ```typescript
  import { BarClient } from '@acme/sdk/foo/bar';
  // Imports only the Bar subpackage

  const client = new BarClient({...});
  ```

  Subpackage exports are also documented in the generated `README.md` when this option is enabled.
</ParamField>

<ParamField path="includeContentHeadersOnFileDownloadResponse" type="boolean" toc={true}>
  Includes the content type and content length from binary responses. The user will receive an object of the following type:

  ```typescript
  {
      data: <BINARY_RESPONSE_TYPE>;
      contentLengthInBytes?: number;
      contentType?: string;
  }
  ```

  `<BINARY_RESPONSE_TYPE>` is `core.BinaryResponse` or a stream, depending on `fileResponseType` setting.
</ParamField>

<ParamField path="includeCredentialsOnCrossOriginRequests" type="boolean" default="false" toc={true}>
  When enabled, [`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) is set to `true` when making network requests.
</ParamField>

<ParamField path="includeOtherInUnionTypes" type="boolean" toc={true} />

<ParamField path="includeUtilsOnUnionMembers" type="boolean" toc={true} />

<ParamField path="inlineFileProperties" type="boolean" default="true" toc={true}>
  Generate file upload properties as inline request properties (instead of positional parameters).

  `inlineFileProperties: false`:

  ```typescript
  /**
    * @param {File | fs.ReadStream} file
    * @param {File[] | fs.ReadStream[]} fileList
    * @param {File | fs.ReadStream | undefined} maybeFile
    * @param {File[] | fs.ReadStream[] | undefined} maybeFileList
    * @param {Acme.MyRequest} request
    * @param {Service.RequestOptions} requestOptions - Request-specific configuration.
    *
    * @example
    *     await client.service.post(fs.createReadStream("/path/to/your/file"), [fs.createReadStream("/path/to/your/file")], fs.createReadStream("/path/to/your/file"), [fs.createReadStream("/path/to/your/file")], {})
    */
  public async post(
      file: File | fs.ReadStream,
      fileList: File[] | fs.ReadStream[],
      maybeFile: File | fs.ReadStream | undefined,
      maybeFileList: File[] | fs.ReadStream[] | undefined,
      request: Acme.MyRequest,
      requestOptions?: Acme.RequestOptions
  ): Promise<void> {
    ...
  }
  ```

  `inlineFileProperties: true`:

  ```typescript
  /**
    * @param {Acme.MyRequest} request
    * @param {Service.RequestOptions} requestOptions - Request-specific configuration.
    *
    * @example
    *     await client.service.post({
    *        file: fs.createReadStream("/path/to/your/file"),
    *        fileList: [fs.createReadStream("/path/to/your/file")]
    *     })
    */
  public async post(
      request: Acme.MyRequest,
      requestOptions?: Service.RequestOptions
  ): Promise<void> {
    ...
  }
  ```
</ParamField>

<ParamField path="inlinePathParameters" type="boolean" default="true" toc={true}>
  Inline path parameters into request types.

  `inlinePathParameters: false`:

  ```typescript
  await service.getFoo("pathParamValue", { id: "SOME_ID" });
  ```

  `inlinePathParameters: true`:

  ```typescript
  await service.getFoo({ pathParamName: "pathParamValue", id: "SOME_ID" });
  ```
</ParamField>

<ParamField path="namespaceExport" type="string" toc={true}>
  Customizes the exported namespace and client class names in the generated SDK. Must be in PascalCase.

  By default, names are derived from the organization and API names defined in your API definition:

  ```typescript
  import { AcmeApi, AcmeApiClient } from "@acme/node";
  ```

  Setting namespaceExport overrides these default names:

  ```yaml title="generators.yml"
  config:
    namespaceExport: AcmePayments
  ```

  ```typescript
  import { AcmePayments, AcmePaymentsClient } from "@acme/node";
  ```
</ParamField>

<ParamField path="neverThrowErrors" type="boolean" default="false" toc={true}>
  When enabled, the client doesn't throw errors when a non-200 response is received from the server. Instead, the response is wrapped in an [`ApiResponse`](https://github.com/fern-api/fern/blob/main/seed/ts-sdk/alias/src/core/fetcher/APIResponse.ts).

  ```typescript
  const response = await client.callEndpoint(...);
  if (response.ok) {
    console.log(response.body)
  } else {
    console.error(respons.error)
  }
  ```
</ParamField>

<ParamField path="noOptionalProperties" type="boolean" default="false" toc={true}>
  By default, Fern's `optional<>` properties will translate to optional TypeScript properties:

  ```yaml {4}
  Person:
    properties:
      name: string
      age: optional<integer>
  ```

  ```typescript {3}
  interface Person {
    name: string;
    age?: number;
  }
  ```

  When `noOptionalProperties` is enabled, the generated properties are never optional. Instead, the type is generated with `| undefined`. As a result, users must explicitly set the property to a value or `undefined`.

  ```typescript {3}
  interface Person {
    name: string;
    age: number | undefined;
  }
  ```
</ParamField>

<ParamField path="noScripts" type="boolean" toc={true}>
  Prevent the generator from running any scripts such as `yarn format` or `yarn install`. If any of the scripts cause errors, toggling this option will allow you to receive the generated code.
</ParamField>

<ParamField path="noSerdeLayer" type="boolean" default="true" toc={true}>
  Controls whether the serde layer is enabled for serialization/deserialization.

  When `noSerdeLayer: false`, the generated client includes custom serialization code that transforms property names to camelCase, validates requests/responses at runtime, and supports complex types.

  See [TypeScript serde layer](/sdks/generators/typescript/serde-layer) for detailed guidance on when to enable this option.
</ParamField>

<ParamField path="outputSourceFiles" type="boolean" default="true" toc={true}>
  Controls the output format of generated files:

  * **When `true` (default)**: Outputs raw TypeScript `.ts` files
  * **When `false`**: Runs TypeScript compiler and outputs compiled `.js` files with `.d.ts` declaration files

  <Note>
    This option only applies when using local file system output. This setting is ignored when publishing to GitHub or npm, where files are always compiled.
  </Note>
</ParamField>

<ParamField path="packageJson" type="object" toc={true}>
  When you specify an object in `packageJson`, it will be merged into the `package.json` file. This is the recommended way to customize your SDK's package.json.

  ```yaml
  # generators.yml
  config:
    packageJson:
      description: The SDK for Acme Corp's API.
      author:
        name: Acme Corp
        url: https://developer.acmecorp.com
        email: developers@acmecorp.com
      bugs:
        url: https://developer.acmecorp.com
        email: developers@acmecorp.com
  ```

  <Note>
    Use the 

    `packageJson`

     config option instead of 

    `.fernignore`

     to prevent package.json from being overwritten.
  </Note>
</ParamField>

<ParamField path="package-name" type="string" default="null" required={false} toc={true}>
  Specifies the TypeScript package name that users will import your generated client
  from.

  For example, setting `package-name: "my_custom_package"` enables users to use
  `my_custom_package import Client` to import your client.
</ParamField>

<ParamField path="packagePath" type="string" toc={true}>
  Specify the path where the source files for the generated SDK should be placed.
</ParamField>

<ParamField path="publishToJsr" type="boolean" toc={true}>
  Publish your SDK to [JSR](https://jsr.io/). When enabled, the generator will
  generate a `jsr.json` as well as a GitHub workflow to publish to JSR.
</ParamField>

<ParamField path="retainOriginalCasing" type="boolean" default="false" toc={true}>
  When enabled, property names in the generated code retain their original casing from the API definition instead of being converted to camelCase.

  ```yaml
  # generators.yml
  config:
    retainOriginalCasing: true
  ```

  **Example with OpenAPI input:**

  ```yaml {7, 9}
  # OpenAPI schema
  components:
    schemas:
      User:
        type: object
        properties:
          user_id:
            type: string
          display_name:
            type: string
  ```

  Generated TypeScript with `retainOriginalCasing: true`:

  ```typescript {2-3}
  export interface User {
    user_id: string;
    display_name: string;
  }
  ```

  Generated TypeScript with default settings (`retainOriginalCasing: false`):

  ```typescript {2-3}
  export interface User {
    userId: string;
    displayName: string;
  }
  ```
</ParamField>

<ParamField path="shouldGenerateWebsocketClients" type="boolean" toc={true}>
  Generate WebSocket clients from your AsyncAPI specs.
</ParamField>

<ParamField path="skipResponseValidation" type="boolean" default="false" toc={true}>
  By default, the client will throw an error if the response from the server
  doesn't match the expected type (based on how the response is modeled in the
  Fern Definition).

  If `skipResponseValidation` is set to `true`, the client will never throw if the response is misshapen. Instead, the client will log the issue using `console.warn` and return the data (casted to the expected response type).

  <Warning>
    Response validation only occurs when the Serde layer is enabled (

    `noSerdeLayer: false`

    ). The Serde layer is disabled by default (

    `noSerdeLayer: true`

    ).
  </Warning>
</ParamField>

<ParamField path="streamType" type="'wrapper' | 'web'" toc={true}>
  Change the type of stream that is used in the generated SDK.

  * `wrapper`: The streams use a wrapper with multiple underlying implementations to support versions of Node.js before Node.js 18.
  * `web`: The streams use the web standard `ReadableStream`.

  The default is `web`.
</ParamField>

<ParamField path="treatUnknownAsAny" type="boolean" default="false" toc={true}>
  When `treatUnknownAsAny` is enabled, [unknown types from Fern are generated into TypeScript using `any` instead of the `unknown` type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type).
</ParamField>

<ParamField path="useBigInt" type="boolean" default="false" toc={true}>
  When `useBigInt` is set to `true`, a customized JSON serializer & deserializer is used that will preserve the precision of `bigint`'s, as opposed to the native `JSON.stringify` and `JSON.parse` function which converts `bigint`'s to number's losing precision.

  When combining `useBigInt` with our serialization layer (`noSerdeLayer: false`), both the request and response properties that are marked as `long` and `bigint` in OpenAPI/Fern spec, will consistently be `bigint`'s.
  However, when disabling the serialization layer (`noSerdeLayer: true`), they will be typed as `number | bigint`. See [TypeScript serde layer](/sdks/generators/typescript/serde-layer) for more information.

  Here's an overview of what to expect from the generated types when combining `useBigInt` and `noSerdeLayer` with the following Fern definition:

  *Fern definition*:

  ```yaml
  types:
    ObjectWithOptionalField:
      properties:
        longProp: long
        bigIntProp: bigint
  ```

  *TypeScript output*:

  ```typescript
  // useBigInt: true
  // noSerdeLayer: false
  interface ObjectWithLongAndBigInt {
    longProp: bigint;
    bigIntProp: bigint;
  }

  // useBigInt: true
  // noSerdeLayer: true
  interface ObjectWithLongAndBigInt {
    longProp: bigint | number;
    bigIntProp: bigint | number;
  }

  // useBigInt: false
  // noSerdeLayer: false
  interface ObjectWithLongAndBigInt {
    longProp: number;
    bigIntProp: string;
  }

  // useBigInt: false
  // noSerdeLayer: true
  interface ObjectWithLongAndBigInt {
    longProp: number;
    bigIntProp: string;
  }
  ```
</ParamField>

<ParamField path="useBrandedStringAliases" type="boolean" default="false" toc={true}>
  When `useBrandedStringAliases` is disabled (the default), string aliases are generated as
  normal TypeScript aliases:

  ```typescript
  // generated code

  export type MyString = string;

  export type OtherString = string;
  ```

  When `useBrandedStringAliases` is enabled, string aliases are generated as branded strings. This makes each alias feel like its own type and improves compile-time safety.

  ```yaml
  # fern definition

  types:
  	MyString: string
  	OtherString: string
  ```

  ```typescript
  // generated code

  export type MyString = string & { __MyString: void };
  export const MyString = (value: string): MyString => value as MyString;

  export type OtherString = string & { __OtherString: void };
  export const OtherString = (value: string): OtherString => value as OtherString;
  ```

  ```typescript
  // consuming the generated type

  function printMyString(s: MyString): void {
    console.log("MyString: " + s);
  }

  // doesn't compile, "foo" is not assignable to MyString
  printMyString("foo");

  const otherString = OtherString("other-string");
  // doesn't compile, otherString is not assignable to MyString
  printMyString(otherString);

  // compiles
  const myString = MyString("my-string");
  printMyString(myString);
  ```
</ParamField>