Generating a TypeScript Axios Client from OpenAPI
A typed HTTP client that stays in lockstep with your spec is the fastest way to stop frontend teams from hand-writing fetch calls. This guide shows the exact OpenAPI Generator invocation to produce a typescript-axios SDK, which --additional-properties actually matter, how to wire it into a build, and how to publish it to npm. It is part of SDK Generation & Changelog Automation and assumes you already have a valid OpenAPI 3.x document.
Problem & Context
Frontend developers consuming your API by hand-writing axios calls produce three recurring problems: request and response types drift from the real API, a renamed field breaks silently at runtime, and every team re-implements auth and error handling. Generating a typescript-axios client solves all three — it ships fully typed request methods, model interfaces, and a single Configuration object for base URL and credentials.
The friction is in the details. The typescript-axios generator has a long list of --additional-properties, and the wrong combination produces a package that will not compile, will not tree-shake, or cannot be published. The three that change the shape of the output most are:
npmName— the package name; without it, the generatedpackage.jsonis incomplete and not publishable.supportsES6— emits ES6 (import/export,const) instead of ES5, required for modern bundlers and tree-shaking.withSeparateModelsAndApi— splits models and APIs into separate directories so a model change does not invalidate every API import.
Step-by-Step Solution
1. Pin the generator version
npm install -g @openapitools/openapi-generator-cli
openapi-generator-cli version-manager set 7.6.0
openapi-generator-cli version
Expected output:
Did set the version to 7.6.0
7.6.0
2. List the generator’s properties (optional but recommended)
Confirm the property names for the version you pinned — they occasionally change between majors.
openapi-generator-cli config-help -g typescript-axios | grep -E "npmName|supportsES6|withSeparateModelsAndApi"
Expected output (truncated):
npmName
The name under which you want to publish generated npm package.
supportsES6
Generate code that conforms to ES6. (Default: false)
withSeparateModelsAndApi
Put the model and api in separate folders ... (Default: false)
3. Generate the client
openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-axios \
-o ./sdk \
--additional-properties=npmName=@acme/api-client,npmVersion=1.0.0,supportsES6=true,withSeparateModelsAndApi=true,useSingleRequestParameter=true
Expected output (truncated):
[main] INFO o.o.codegen.DefaultGenerator - Generated server response code: ...
[main] INFO o.o.codegen.TemplateManager - writing file ./sdk/api/default-api.ts
[main] INFO o.o.codegen.TemplateManager - writing file ./sdk/models/index.ts
[main] INFO o.o.codegen.TemplateManager - writing file ./sdk/package.json
[main] INFO o.o.codegen.DefaultGenerator - Generation took: ... ms
Confirm the package name and layout:
grep '"name"' ./sdk/package.json && ls ./sdk
Expected output:
"name": "@acme/api-client",
api base.ts common.ts configuration.ts index.ts models package.json tsconfig.json
4. Build the package
The generator emits TypeScript and a package.json whose build script runs tsc. Compile to JavaScript plus declaration files before doing anything else.
cd sdk
npm install
npm run build
ls dist
Expected output:
api.js api.d.ts configuration.js configuration.d.ts index.js index.d.ts models
5. Wire it into a consuming app
// usage.ts — in the app that depends on @acme/api-client
import { Configuration, DefaultApi } from '@acme/api-client';
const api = new DefaultApi(
new Configuration({
basePath: 'https://api.acme.com',
accessToken: () => localStorage.getItem('token') ?? '',
}),
);
const { data } = await api.listOrders();
console.log(data.length);
6. Publish to npm
cd sdk
npm publish --access public
Expected output:
+ @acme/[email protected]
Complete Working Example
A GitHub Actions workflow that regenerates, builds, and publishes the SDK whenever the spec changes — the full pipeline in one self-contained file.
# .github/workflows/publish-sdk.yml
name: Publish TypeScript SDK
on:
push:
branches: [main]
paths: ['openapi.yaml']
jobs:
generate-build-publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
# Pin the generator so CI output is deterministic.
- name: Pin OpenAPI Generator
run: npx --yes @openapitools/openapi-generator-cli version-manager set 7.6.0
# Generate the typescript-axios client with the properties that shape the output.
- name: Generate SDK
run: |
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-axios \
-o ./sdk \
--additional-properties=npmName=@acme/api-client,npmVersion=1.0.${{ github.run_number }},supportsES6=true,withSeparateModelsAndApi=true,useSingleRequestParameter=true
# Compile TypeScript to JS + .d.ts. Publishing source-only would break consumers.
- name: Build
working-directory: ./sdk
run: |
npm install
npm run build
# Publish. NPM_TOKEN must be a repository secret with publish rights.
- name: Publish to npm
working-directory: ./sdk
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Gotchas & Edge Cases
supportsES6=false silently breaks tree-shaking. The default emits ES5 with module.exports, which modern bundlers cannot tree-shake, so consumers ship the entire client even if they call one method. Always set supportsES6=true for a browser-bound SDK.
Publishing source instead of dist forces consumers to compile your SDK. If you skip npm run build and publish the raw .ts files, every project that installs the package has to transpile it. Confirm package.json has "main": "dist/index.js" and "types": "dist/index.d.ts", and that dist is included in files or not excluded by .npmignore.
operationId collisions produce duplicate method names. Two operations sharing an operationId generate the same TypeScript method, and the second overwrites the first. Lint the spec for unique operationId values before generating, or the SDK will silently drop a method.
FAQ
Which OpenAPI Generator should I use for a TypeScript Axios client?
Use the typescript-axios generator, which produces a fetch-free client built on the axios HTTP library with full TypeScript types. It is the right choice when your app already uses axios or you want interceptors for auth and retries.
How do I set the npm package name when generating?
Pass npmName through --additional-properties, for example --additional-properties=npmName=@acme/api-client. The generator writes a package.json with that name so the output is ready to build and publish.
Do I need to compile the generated client before publishing?
Yes. The generator emits TypeScript source plus a package.json with a build script, so run npm install and npm run build to produce the .js and .d.ts files before npm publish. Publishing the raw .ts files would force every consumer to compile your SDK.
Related
- OpenAPI Generator — parent guide to generators, config, and CI patterns
- Customizing OpenAPI Generator Templates
- Handling oneOf Discriminators in Generated SDKs
- SDK Generation & Changelog Automation