Documentation

OpenAPI Sync is a powerful developer tool that automates the generation of TypeScript types, API clients (Fetch, Axios, React Query, SWR, RTK Query), runtime validation schemas (Zod, Yup, Joi), and endpoint definitions from your OpenAPI specifications in real-time.

Latest Version: 6.4.2 - add official Model Context Protocol Registry verification with mcpName declaration

Getting Started with OpenAPI Sync

Duration: 0:10

Learn the basics of OpenAPI Sync and how it can automate your API development workflow.

Watch on YouTube

Installation

Installation & Setup

Duration: 0:10

Step-by-step guide to installing and configuring OpenAPI Sync in your project.

Watch on YouTube

Install OpenAPI Sync using your preferred package manager:

bash
# NPM
npm install openapi-sync

# Yarn
yarn add openapi-sync

# PNPM
pnpm add openapi-sync

# Global Installation
npm install -g openapi-sync

# Direct Usage (No Installation)
npx openapi-sync

โš ๏ธ macOS Big Sur Users: If you encounter an esbuild installation error (Symbol not found: _SecTrustCopyCertificateChain), please install esbuild@0.17.19 first: npm install esbuild@0.17.19 then install openapi-sync. See Troubleshooting for details.

Quick Start

Quick Start Tutorial

Duration: 0:10

Get up and running with OpenAPI Sync in under 5 minutes with this quick start guide.

Watch on YouTube

1. Create Configuration

Create a configuration file in your project root:

json
// openapi.sync.json
{
  "refetchInterval": 5000,
  "folder": "./src/api",
  "api": {
    "petstore": "https://petstore3.swagger.io/api/v3/openapi.json"
  }
}

2. Run Sync Command

bash
npx openapi-sync

3. Use Generated Code

typescript
import { getPetById } from "./src/api/petstore/endpoints";
import { IPet } from "./src/api/petstore/types";

// Use the endpoint URL
const petUrl = getPetById("123"); // Returns: "/pet/123"

// Use the generated types
const pet: IPet = {
  id: 1,
  name: "Fluffy",
  status: "available"
};

Presets

Zero-Config

Presets bundle opinionated defaults for popular frameworks, HTTP clients, and runtime validation libraries into a single name. Instead of configuring dozens of settings manually, simply select a preset during npx openapi-sync init or declare "preset": "<name>" in your config file. Any explicit configuration you provide will cleanly override preset defaults.

Available Presets

Preset NameTarget Framework / HTTP ClientValidation LibraryFeatures ConfiguredDependencies
react-query-zod
Recommended
TanStack React Query v5ZodTyped Query & Mutation hooks, Zod schemas, preserved custom code, operationId namingnpm i @tanstack/react-query axios zod
react-query-yupTanStack React Query v5YupTyped Query & Mutation hooks, Yup validation schemas, preserved custom codenpm i @tanstack/react-query axios yup
swr-zodVercel SWRZodSWR hooks with mutation support (useSWRMutation), Zod schemas, preserved custom codenpm i swr axios zod
swr-yupVercel SWRYupSWR hooks with mutation support, Yup schemas, preserved custom codenpm i swr axios yup
axios-zodAxios ClientZodStandalone typed Axios client instance, Zod schemas, preserved custom codenpm i axios zod
axios-joiAxios ClientJoiStandalone typed Axios client, Joi validation schemas (great for Node.js backends)npm i axios joi
fetch-zodNative Fetch APIZodZero-dependency native fetch client, Zod runtime validationnpm i zod
rtk-query-zodRedux Toolkit QueryZodRTK Query API slice definitions with fetchBaseQuery, Zod schemasnpm i @reduxjs/toolkit react-redux zod
next-fetchNext.js (App / Pages router)DisabledServer Components-friendly fetch calls with caching headers, validation disabled for zero bundle bloatBuilt-in
python-basicPythonN/AGenerates Python dataclasses / TypedDict types, no TypeScript runtime validationpip install requests

How to Use Presets

1. Via Setup Wizard: Run npx openapi-sync init and select your preset. Questions matching the preset will be automatically configured for you.

2. In JSON Configuration (openapi.sync.json):

json
{
  "$schema": "./node_modules/openapi-sync/openapi.sync.schema.json",
  "preset": "react-query-zod",
  "api": {
    "petstore": "https://petstore3.swagger.io/api/v3/openapi.json"
  }
}

3. In TypeScript (openapi.sync.ts) with defineConfig:

typescript
import { defineConfig } from "openapi-sync";

export default defineConfig({
  preset: "react-query-zod",
  api: {
    petstore: "https://petstore3.swagger.io/api/v3/openapi.json",
  },
  // Overrides: User values always take precedence over preset defaults
  folder: "./src/api",
});

Basic Configuration

Basic Configuration

Duration: 0:10

Learn how to configure OpenAPI Sync with JSON, TypeScript, or JavaScript config files.

Watch on YouTube

OpenAPI Sync supports multiple configuration formats:

  • openapi.sync.json - JSON format
  • openapi.sync.ts - TypeScript format
  • openapi.sync.js - JavaScript format

Configuration Options

PropertyTypeDescription
presetstringPre-configured framework preset (e.g. "react-query-zod", "swr-zod"). See Presets.
refetchIntervalnumberMilliseconds between API refetches (dev only)
folderstringOutput directory for generated files
apiRecord<string, string>Map of API names to OpenAPI spec URLs
servernumber | stringServer index or custom server URL

Protected Specs & Authentication

OpenAPI Sync can fetch specs protected behind Bearer tokens, Basic auth, API keys, or custom headers.

โš ๏ธ Important for Developers & AI Agents

Referencing environment variables for credentials requires using a TypeScript (openapi.sync.ts) or JavaScript (openapi.sync.js) configuration file. Static JSON (openapi.sync.json) does not evaluate JavaScript runtime expressions like process.env and will cause JSON syntax errors.

typescript
// openapi.sync.ts
import { defineConfig } from "openapi-sync";

export default defineConfig({
  api: {
    // 1. Bearer Token
    billingApi: {
      url: "https://api.example.com/billing/openapi.json",
      auth: {
        type: "bearer",
        token: process.env.BILLING_API_TOKEN!,
      },
    },

    // 2. Basic Auth
    internalApi: {
      url: "https://internal.example.com/spec.json",
      auth: {
        type: "basic",
        username: process.env.INTERNAL_USER!,
        password: process.env.INTERNAL_PASSWORD!,
      },
    },

    // 3. API Key in Header or Query
    analyticsApi: {
      url: "https://analytics.example.com/openapi.json",
      auth: {
        type: "apiKey",
        in: "header",
        name: "X-API-Key",
        value: process.env.ANALYTICS_KEY!,
      },
    },

    // 4. Custom Headers
    customApi: {
      url: "https://api.example.com/spec.json",
      auth: {
        type: "custom",
        headers: {
          "X-Organization-Id": "org_12345",
          "X-Api-Secret": process.env.API_SECRET!,
        },
      },
    },

    // 5. Automatic ${env.VAR} placeholder resolution
    // (Automatically reads from .env, .env.local, or next.config.js)
    envResolvedApi: {
      url: "https://api.example.com/spec.json",
      auth: {
        type: "bearer",
        token: "${env.SPEC_ACCESS_TOKEN}",
      },
    },
  },
});

Folder Splitting

Folder Splitting & Organization

Duration: 0:10

Organize your generated code by tags or custom logic for better project structure.

Watch on YouTube

Organize your generated code into folders based on tags or custom logic.

Split by Tags

typescript
folderSplit: {
  byTags: true  // Creates folders like admin/, user/, pet/
}

Custom Folder Logic

typescript
folderSplit: {
  customFolder: ({ method, path, tags, operationId }) => {
    // Admin endpoints go to admin folder
    if (tags?.includes("admin")) return "admin";
    
    // API versioning
    if (path.startsWith("/api/v1/")) return "v1";
    if (path.startsWith("/api/v2/")) return "v2";
    
    // Method-based organization
    if (method === "GET") return "read";
    if (method === "POST" || method === "PUT") return "write";
    
    return null; // Use default structure
  }
}

Generated Structure

text
src/api/
โ”œโ”€โ”€ petstore/
โ”‚   โ”œโ”€โ”€ admin/
โ”‚   โ”‚   โ”œโ”€โ”€ endpoints.ts
โ”‚   โ”‚   โ””โ”€โ”€ types.ts
โ”‚   โ”œโ”€โ”€ user/
โ”‚   โ”‚   โ”œโ”€โ”€ endpoints.ts
โ”‚   โ”‚   โ””โ”€โ”€ types.ts
โ”‚   โ””โ”€โ”€ pet/
โ”‚       โ”œโ”€โ”€ endpoints.ts
โ”‚       โ””โ”€โ”€ types.ts
โ””โ”€โ”€ shared.ts

Validation Schemas

Runtime Validation with Zod, Yup & Joi

Duration: 0:10

Generate and use runtime validation schemas for type-safe API requests.

Watch on YouTube

Generate runtime validation schemas using Zod, Yup, or Joi from your OpenAPI specification.

Configuration

typescript
validations: {
  library: "zod",  // "zod" | "yup" | "joi"
  generate: {
    query: true,   // Generate query parameter validations
    dto: true      // Generate request body validations
  },
  name: {
    prefix: "I",
    suffix: "Schema",
    useOperationId: true
  }
}

Installation

bash
# For Zod
npm install zod

# For Yup
npm install yup

# For Joi
npm install joi

Usage Example

typescript
import { IAddPetDTOSchema } from "./src/api/petstore/validation";
import { z } from "zod";

// Validate request body
try {
  const validatedData = IAddPetDTOSchema.parse(req.body);
  // Data is now validated and typed
} catch (error) {
  if (error instanceof z.ZodError) {
    console.error("Validation errors:", error.errors);
  }
}

Express Middleware

typescript
import { Request, Response, NextFunction } from "express";
import { z } from "zod";

export const validate = <T extends z.ZodTypeAny>(schema: T) => {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      schema.parse(req.body);
      next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          error: "Validation failed",
          details: error.errors
        });
      }
    }
  };
};

// Usage
import { IAddPetDTOSchema } from "./api/validation";
router.post("/pet", validate(IAddPetDTOSchema), handler);

Custom Code Preservation

Custom Code Preservation

Duration: 0:10

Learn how to add custom code that survives regeneration using special markers.

Watch on YouTube

Add your own custom code that will survive when files are regenerated.

Configuration

typescript
customCode: {
  enabled: true,              // Enable custom code preservation
  position: "bottom",         // "top" | "bottom" | "both"
  markerText: "CUSTOM CODE",  // Custom marker text
  includeInstructions: true   // Include helpful instructions
}

Usage

typescript
// endpoints.ts (after generation)
export const getPet = (petId: string) => `/pet/${petId}`;

// ๐Ÿ”’ CUSTOM CODE START
// Add your custom code here - it will be preserved
export const legacyGetPet = (id: string) => `/api/v1/pet/${id}`;

export const buildPetUrl = (petId: string, includePhotos: boolean) => {
  const base = getPet(petId);
  return includePhotos ? `${base}?include=photos` : base;
};
// ๐Ÿ”’ CUSTOM CODE END

export const updatePet = (petId: string) => `/pet/${petId}`;

Endpoint Filtering

Endpoint Filtering & Selection

Duration: 0:10

Filter endpoints by tags, paths, or regex patterns to control what gets generated.

Watch on YouTube

Control which endpoints are included in code generation.

Exclude Endpoints

typescript
endpoints: {
  exclude: {
    // Exclude by tags
    tags: ["deprecated", "internal"],
    
    // Exclude specific endpoints
    endpoints: [
      { path: "/admin/users", method: "DELETE" },
      { regex: "^/internal/.*", method: "GET" },
      { path: "/debug" }  // All methods
    ]
  }
}

Include Only Specific Endpoints

typescript
endpoints: {
  include: {
    // Include only public endpoints
    tags: ["public"],
    
    // Include specific endpoints
    endpoints: [
      { path: "/public/users", method: "GET" },
      { regex: "^/public/.*" }
    ]
  }
}

Python Code Generation ๐Ÿ

In addition to TypeScript, OpenAPI Sync supports generating type-safe Python data structures and endpoint definitions directly from your OpenAPI specifications using native @dataclass models.

Configuration

Set language: "python" in your API configuration block:

typescript
// openapi.sync.json or openapi.sync.ts
export default {
  apis: [
    {
      name: "petstore_py",
      url: "https://petstore.swagger.io/v2/swagger.json",
      destination: "./src/api/petstore_py",
      language: "python", // ๐Ÿ Generates types.py and endpoints.py
      folderSplit: {
        byTags: true
      }
    }
  ]
};

Generated Python Models (types.py)

Generated types use standard Python typing (Optional, List, Union, Dict) and @dataclass decorators, with automatic keyword and character sanitization:

python
from dataclasses import dataclass
from typing import Optional, List, Union, Dict, Any

@dataclass
class Pet:
    """Pet model schema
    
    Attributes:
        id: Unique identifier for the pet
        name: Name of the pet
        category: Pet category
        status: Pet status in the store
    """
    id: Optional[int] = None
    name: Optional[str] = None
    category: Optional["Category"] = None
    status: Optional[str] = None

@dataclass
class GetPetByIdQuery:
    include_deleted: Optional[bool] = None

Generated Python Endpoints (endpoints.py)

Python endpoints include typed URL builder methods, method constants, and docstrings with cURL examples:

python
class Endpoint:
    def __init__(self, name: str, path: str, method: str, url):
        self.name = name
        self.path = path
        self.method = method
        self.url = url

class Endpoints:
    GET_PET_BY_ID = Endpoint(
        name="getPetById",
        path="/pet/{petId}",
        method="GET",
        url=lambda petId: f"/pet/{petId}"
    )

API Client Generation

Automatically generate fully-typed API clients and hooks for popular libraries directly from your OpenAPI specifications.

Generate clients for Fetch, Axios, React Query, SWR, and RTK Query with full TypeScript support!

API Client Generation Overview

Duration: 0:10

Introduction to generating fully-typed API clients from your OpenAPI specification.

Watch on YouTube

Supported Client Types

  • fetch - Native browser Fetch API with TypeScript types
  • axios - Axios client with interceptors and error handling
  • react-query - React Query/TanStack Query hooks (v4 & v5)
  • swr - SWR hooks for React
  • rtk-query - Redux Toolkit Query API slice

Basic Usage

bash
# Generate Fetch client
npx openapi-sync generate-client --type fetch

# Generate Axios client
npx openapi-sync generate-client --type axios

# Generate React Query hooks
npx openapi-sync generate-client --type react-query

# Generate SWR hooks
npx openapi-sync generate-client --type swr

# Generate RTK Query API
npx openapi-sync generate-client --type rtk-query

Filter by Tags or Endpoints

Generate clients for specific endpoints only:

bash
# Filter by tags
npx openapi-sync generate-client --type fetch --tags pets,users

# Filter by endpoint names
npx openapi-sync generate-client --type axios --endpoints getPetById,createPet

# Generate for specific API
npx openapi-sync generate-client --type react-query --api petstore

# Specify output directory
npx openapi-sync generate-client --type swr --output ./src/clients

# Set base URL
npx openapi-sync generate-client --type fetch --base-url https://api.example.com

React Query Example

Complete example using React Query hooks:

typescript
// 1. Generate the client
// npx openapi-sync generate-client --type react-query

// 2. Setup in your app
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import apiClient from "./api/petstore/client/client";

// Configure API client
apiClient.updateConfig({
  baseURL: "https://api.example.com",
  headers: {
    Authorization: "Bearer your-auth-token",
  },
});

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <YourComponent />
    </QueryClientProvider>
  );
}

// 3. Use in components
import { useGetPetById, useCreatePet } from "./api/petstore/client/hooks";

function PetDetails({ petId }: { petId: string }) {
  // Query hook for GET requests
  const { data, isLoading, error } = useGetPetById({ petId });

  // Mutation hook for POST/PUT/PATCH/DELETE
  const createPet = useCreatePet({
    onSuccess: (newPet) => {
      console.log("Pet created:", newPet);
    },
  });

  const handleCreate = () => {
    createPet.mutate({
      data: {
        name: "Fluffy",
        species: "cat",
      },
    });
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>{data?.name}</h1>
      <p>Status: {data?.status}</p>
      <button onClick={handleCreate}>Create New Pet</button>
    </div>
  );
}

Fetch Client Example

typescript
import { setApiConfig, getPetById, createPet } from "./api/petstore/client";

// Configure the client
setApiConfig({
  baseURL: "https://api.example.com",
  auth: { token: "your-token" },
  headers: {
    "X-Custom-Header": "value",
  },
});

// Use the client
async function fetchPet(petId: string) {
  try {
    const pet = await getPetById({ petId });
    console.log("Pet:", pet);
  } catch (error) {
    if (error instanceof ApiError) {
      console.error("API Error:", error.statusCode, error.response);
    }
  }
}

async function addNewPet() {
  const newPet = await createPet({
    data: {
      name: "Max",
      species: "dog",
      age: 3,
    },
  });
  console.log("Created:", newPet);
}

Axios Client Example

typescript
import apiClient from "./api/petstore/client";

// Configure the client
apiClient.updateConfig({
  baseURL: "https://api.example.com",
  timeout: 10000,
  headers: {
    "X-App-Version": "1.0.0",
    Authorization: "Bearer your-auth-token",
  },
});

// Use the client
async function example() {
  // GET request
  const pet = await apiClient.getPetById({ petId: "123" });
  
  // POST request
  const newPet = await apiClient.createPet({
    data: {
      name: "Buddy",
      species: "dog",
    },
  });
  
  // PUT request
  await apiClient.updatePet(
    { petId: "123" },
    { name: "Buddy Updated" }
  );
  
  // DELETE request
  await apiClient.deletePet({ petId: "123" });
}

SWR Hooks Example

typescript
import { useGetPetById, useCreatePet } from "./api/petstore/client/hooks";

function PetProfile({ petId }: { petId: string }) {
  // SWR automatically handles caching, revalidation, and more
  const { data, error, isLoading, mutate } = useGetPetById({ petId });

  const { trigger, isMutating } = useCreatePet();

  const handleCreate = async () => {
    try {
      const newPet = await trigger({
        arg: {
          data: {
            name: "Charlie",
            species: "cat",
          },
        },
      });
      // Revalidate the pet list
      mutate();
    } catch (err) {
      console.error("Failed to create pet:", err);
    }
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error loading pet</div>;

  return (
    <div>
      <h2>{data?.name}</h2>
      <button onClick={handleCreate} disabled={isMutating}>
        {isMutating ? "Creating..." : "Create New Pet"}
      </button>
    </div>
  );
}

RTK Query Example

typescript
// 1. Setup store
import { configureStore } from "@reduxjs/toolkit";
import { apiApi } from "./api/petstore/client/api";

export const store = configureStore({
  reducer: {
    [apiApi.reducerPath]: apiApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(apiApi.middleware),
});

// 2. Use in components
import { useGetPetByIdQuery, useCreatePetMutation } from "./api/petstore/client/api";

function PetCard({ petId }: { petId: string }) {
  const { data, isLoading, error } = useGetPetByIdQuery({ 
    params: { petId } 
  });
  
  const [createPet, { isLoading: isCreating }] = useCreatePetMutation();

  const handleCreate = async () => {
    try {
      await createPet({
        data: {
          name: "Luna",
          species: "cat",
        },
      }).unwrap();
      alert("Pet created!");
    } catch (err) {
      console.error("Failed:", err);
    }
  };

  return (
    <div>
      {isLoading && <div>Loading...</div>}
      {error && <div>Error!</div>}
      {data && (
        <div>
          <h3>{data.name}</h3>
          <p>{data.species}</p>
        </div>
      )}
      <button onClick={handleCreate} disabled={isCreating}>
        Create Pet
      </button>
    </div>
  );
}

Generated File Structure

text
api/
โ””โ”€โ”€ petstore/
    โ”œโ”€โ”€ client/
    โ”‚   โ”œโ”€โ”€ client.ts      # Base API client
    โ”‚   โ”œโ”€โ”€ hooks.ts       # React Query/SWR hooks
    โ”‚   โ”œโ”€โ”€ api.ts         # RTK Query API (if applicable)
    โ”‚   โ”œโ”€โ”€ index.ts       # Exports
    โ”‚   โ””โ”€โ”€ README.md      # Usage documentation
    โ”œโ”€โ”€ endpoints.ts
    โ”œโ”€โ”€ types/
    โ”‚   โ”œโ”€โ”€ index.ts
    โ”‚   โ””โ”€โ”€ shared.ts
    โ””โ”€โ”€ validations.ts

Configuration Options

typescript
// openapi.sync.ts
import { IConfig } from "openapi-sync/types";

const config: IConfig = {
  folder: "./src/api",
  api: {
    petstore: "https://petstore3.swagger.io/api/v3/openapi.json",
  },
  // Client generation configuration
  clientGeneration: {
    enabled: true,
    type: "react-query",
    baseURL: "https://api.example.com",
    tags: ["pets", "users"],  // Optional: filter by tags
    endpoints: ["getPetById"], // Optional: specific endpoints
    auth: {
      type: "bearer",
      in: "header",
    },
    errorHandling: {
      generateErrorClasses: true,
    },
    reactQuery: {
      version: 5,
      mutations: true,
      infiniteQueries: false,
    },
  },
};

export default config;

Custom Code Preservation

Generated clients preserve your custom code during regeneration:

typescript
// client.ts (Generated)

// Auto-generated client code...

// ============================================================
// ๐Ÿ”’ CUSTOM CODE START
// Add your custom code below this line
// This section will be preserved during regeneration
// ============================================================

// Your custom helper functions
export function buildPaginatedUrl(
  baseUrl: string,
  page: number,
  limit: number
) {
  return `${baseUrl}?page=${page}&limit=${limit}`;
}

// Custom interceptors
export function setupCustomInterceptors() {
  // Your custom logic
}

// ๐Ÿ”’ CUSTOM CODE END
// ============================================================

CLI Options Reference

OptionDescriptionExample
--type, -tClient type to generate (required)fetch, axios, react-query, swr, rtk-query
--api, -aSpecific API from config--api petstore
--tagsFilter by endpoint tags--tags pets,users
--endpoints, -eFilter by endpoint names--endpoints getPetById,createPet
--output, -oOutput directory--output ./src/clients
--base-url, -bBase URL for requests--base-url https://api.example.com

New in v5.0.0: All client generators now include comprehensive inline documentation, better ESLint compliance, and improved folder splitting support!

RTK Query Enhancements (v5.0.0)

Simplified Redux Store Setup

When using folder splitting, RTK Query now generates an apis.ts file with a helper object that makes Redux store configuration incredibly simple:

typescript
// Before v5.0.0 (Complex setup)
import { configureStore } from '@reduxjs/toolkit';
import { petsApi } from './pets/api';
import { usersApi } from './users/api';
import { ordersApi } from './orders/api';

export const store = configureStore({
  reducer: {
    [petsApi.reducerPath]: petsApi.reducer,
    [usersApi.reducerPath]: usersApi.reducer,
    [ordersApi.reducerPath]: ordersApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      .concat(petsApi.middleware)
      .concat(usersApi.middleware)
      .concat(ordersApi.middleware),
});
typescript
// After v5.0.0 (Simple setup!)
import { configureStore } from '@reduxjs/toolkit';
import { setupApiStore } from './api/petstore/apis';

export const store = configureStore({
  reducer: setupApiStore.reducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(setupApiStore.middleware),
});

// That's it! All API slices are automatically configured โœจ

Unique Reducer Paths

Each API slice now has a unique reducerPath based on its folder name, preventing conflicts:

typescript
// Generated pets/api.ts
const petsApi = createApi({
  reducerPath: 'petsApi',  // โœ… Unique!
  // ...
});

// Generated users/api.ts
const usersApi = createApi({
  reducerPath: 'usersApi',  // โœ… Unique!
  // ...
});

// No more "Duplicate property" TypeScript errors!

Default Exports for Better Imports

API slices now export as default, making imports cleaner:

typescript
// Clean default import
import petsApi from './pets/api';
import { useGetPetsQuery } from './pets/api';

// Or use the aggregated apis.ts
import { petsApi, useGetPetsQuery } from './apis';

SWR Improvements (v5.0.0)

Fixed Mutation Type Errors

SWR mutation hooks now have correct TypeScript types, fixing the double-nesting issue:

typescript
// v5.0.0 - Correct types! โœ…
export function useCreatePet(
  config?: SWRMutationConfiguration<
    Pet,
    Error,
    string,
    { data: PetRequest }  // Correct: single level
  >
) {
  return useSWRMutation(
    'createPet',
    async (_, { arg }: { arg: { data: PetRequest } }) => {
      return apiClient.createPet(arg);
    },
    config
  );
}

// Usage - works perfectly!
const { trigger } = useCreatePet();
await trigger({ arg: { data: { name: 'Fluffy' } } });

Comprehensive Inline Documentation

Every generated SWR hooks file now includes 230+ lines of usage examples and patterns:

typescript
/**
 * SWR Hooks - Complete Usage Guide
 * 
 * ## Quick Start
 * 
 * 1. Configure SWR globally:
 * ```typescript
 * <SWRConfig value={{ revalidateOnFocus: false }}>
 *   {children}
 * </SWRConfig>
 * ```
 * 
 * ## Examples
 * 
 * ### Reading Data (GET)
 * ```typescript
 * const { data, error, isLoading } = useGetPets();
 * ```
 * 
 * ### Creating Data (POST)
 * ```typescript
 * const { trigger, isMutating } = useCreatePet();
 * await trigger({ arg: { data: { name: 'Luna' } } });
 * ```
 * 
 * ### Optimistic Updates
 * ```typescript
 * revalidate({ ...data, name: newName }, false);
 * await trigger({ arg: { ... } });
 * await revalidate(); // Sync with server
 * ```
 * 
 * [... 200+ more lines of examples ...]
 */

Fetch Client Fixes (v5.0.0)

Fixed Naming Conflicts

Endpoint imports are now automatically aliased to prevent naming conflicts:

typescript
// Generated imports (aliased to avoid conflicts)
import {
  getPets as getPets_endpoint,
  getPetById as getPetById_endpoint,
  createPet as createPet_endpoint,
} from './endpoints';

// Generated functions (no conflict!)
export async function getPets() {
  const _url = getPets_endpoint;  // Uses aliased import
  return fetchAPI(_url, { method: 'GET' });
}

export async function getPetById(params: { url: { id: string } }) {
  const _url = getPetById_endpoint(params.url.id);  // Uses aliased import
  return fetchAPI(_url, { method: 'GET' });
}

ESLint-Compliant Default Exports

Default exports now use named variables, satisfying ESLint rules:

typescript
// v5.0.0 - ESLint compliant! โœ…
const apiClient = {
  setApiConfig,
  getPets,
  getPetById,
  createPet,
};

export default apiClient;

// No more "Assign object to variable" ESLint warnings!

File Organization Improvements (v5.0.0)

Non-Folder-Split Mode

When folder splitting is disabled, files are now generated directly at the root level:

text
api/
โ””โ”€โ”€ petstore/
    โ”œโ”€โ”€ clients.ts       # All API client functions
    โ”œโ”€โ”€ hooks.ts         # All React Query/SWR hooks  
    โ”œโ”€โ”€ endpoints.ts     # Endpoint definitions
    โ”œโ”€โ”€ types.ts         # TypeScript types
    โ””โ”€โ”€ validations.ts   # Validation schemas

# Clean, simple structure for smaller APIs!

Folder-Split Mode

With folder splitting, each tag gets its own folder with complete isolation:

text
api/
โ””โ”€โ”€ petstore/
    โ”œโ”€โ”€ clients.ts       # Aggregates all clients (Fetch/Axios)
    โ”œโ”€โ”€ hooks.ts         # Aggregates all hooks (React Query/SWR)
    โ”œโ”€โ”€ apis.ts          # Aggregates all APIs (RTK Query) + setupApiStore
    โ”œโ”€โ”€ pets/
    โ”‚   โ”œโ”€โ”€ client.ts    # Pet-specific client
    โ”‚   โ”œโ”€โ”€ hooks.ts     # Pet-specific hooks
    โ”‚   โ”œโ”€โ”€ api.ts       # Pet-specific RTK Query API
    โ”‚   โ”œโ”€โ”€ types.ts     # Pet-specific types
    โ”‚   โ””โ”€โ”€ endpoints.ts # Pet-specific endpoints
    โ””โ”€โ”€ users/
        โ”œโ”€โ”€ client.ts
        โ”œโ”€โ”€ hooks.ts
        โ”œโ”€โ”€ api.ts
        โ”œโ”€โ”€ types.ts
        โ””โ”€โ”€ endpoints.ts

# Perfect for large APIs with many endpoints!

๐Ÿ’ก Migration Tip: To get all these improvements, simply regenerate your clients:

bash
npx openapi-sync generate-client --type [your-type]

All improvements are backwards compatible - your existing code will continue to work!

CLI Usage

CLI Commands & Options

Duration: 0:10

Master the OpenAPI Sync CLI with all available commands and options.

Watch on YouTube
bash
# Sync API types and endpoints
npx openapi-sync

# Generate API client
npx openapi-sync generate-client --type react-query

# Run with custom refetch interval
npx openapi-sync --refreshinterval 30000
npx openapi-sync -ri 30000

# Get help
npx openapi-sync --help
npx openapi-sync generate-client --help

Non-Interactive Project Initialization

Initialize openapi-sync non-interactively without stdin prompts โ€” ideal for CI/CD pipelines and AI agent automation. Configure spec authentication directly during initialization:

bash
# Standard non-interactive setup
npx openapi-sync init --no-interactive \
  --api-name petstore \
  --api-url https://petstore3.swagger.io/api/v3/openapi.json \
  --output-folder ./src/api \
  --client-type react-query \
  --validation-library zod \
  --config-format typescript \
  --json

# Initialize with authentication for protected specs
npx openapi-sync init --no-interactive \
  --api-name backend \
  --api-url https://api.example.com/openapi.json \
  --auth-type bearer \
  --auth-token '${env.SPEC_TOKEN}' \
  --preset react-query-zod \
  --run-sync \
  --json

Zero-Config CLI Execution & Config Overrides

You can run openapi-sync completely from terminal scripts without creating any configuration file on disk. Pass any property supported by the configuration file via CLI flags:

bash
# Zero-config sync with preset
npx openapi-sync --api-url https://petstore3.swagger.io/api/v3/openapi.json --preset react-query-zod --folder ./src/api

# Zero-config sync with protected spec
npx openapi-sync --api-url https://api.example.com/openapi.json --auth-type bearer --auth-token "$MY_TOKEN" --preset next-fetch

# Multiple APIs via CLI
npx openapi-sync --api users=https://api.example.com/users.json --api billing=https://api.example.com/billing.json --preset axios-zod

# Override existing disk config properties on-the-fly
npx openapi-sync --folder ./dist/api --validation-lib yup --no-docs

# Raw JSON configuration via CLI
npx openapi-sync --config-json '{"api":{"main":"https://api.example.com/spec.json"},"preset":"react-query-zod"}'

CLI Improvements

CLI Arguments Override Config

CLI options now correctly override configuration file settings:

bash
# Config file says type: "fetch"
# But CLI argument takes precedence:
npx openapi-sync generate-client --type rtk-query

# Result: Generates RTK Query (not Fetch) โœ…

# This works for all options:
npx openapi-sync generate-client \
  --type swr \
  --base-url https://api.example.com \
  --tags pets,users

# CLI values override config values!

Streamlined Interactive Setup

The interactive setup wizard is now simpler - selecting folder splitting automatically enables tag-based organization:

bash
# npx openapi-sync init

? Organize generated code into folders by OpenAPI tags? Yes
# โœ… Automatically enables byTags: true
# (No extra question needed!)

? Generate API client code? Yes
? Which client type would you like? React Query
# ... continues with setup

Machine-Readable Output (CI/CD & Agent-Safe)

All commands support --json for structured stdout output and --silent to suppress all logs. Ideal for scripting, CI pipelines, and AI agent integrations:

bash
# Sync and get a structured JSON result
npx openapi-sync --json

# Validate config without writing files
npx openapi-sync validate --json

# List all endpoints as JSON
npx openapi-sync list-endpoints --json

# Page/search endpoint discovery for large specs
npx openapi-sync list-endpoints --api petstore --path-contains pet --limit 10 --offset 0 --json

# Inspect one endpoint in full detail
npx openapi-sync get-endpoint --api petstore --operation-id getPetById --json

# Read one generated TypeScript declaration
npx openapi-sync read-type --api petstore --type-name Pet --json

# Generate client with JSON output (great for agents)
npx openapi-sync generate-client --type react-query --json

# Silent mode (no stdout noise) โ€” exit code tells you the result
npx openapi-sync --silent && echo "Sync OK!"

Tip: The --json flag implies --silent. The process exit code is 0 on success and 1 on failure, so it works naturally in shell pipelines and CI checks.

๐Ÿฉบ Diagnostic Doctor

The doctor command provides automated self-healing and environment diagnostics. It audits your configuration syntax, specification reachability over the network, installed validation peer dependencies (Zod, Yup, Joi), schema cache integrity, and filesystem write permissions.

bash
# Run the human-readable diagnostic report
npx openapi-sync doctor

# Machine-readable output for CI/CD checks or AI agents
npx openapi-sync doctor --json

Automated Health Checks Performed

  • Configuration File: Verifies that openapi.sync.ts, .js, or .json exists and parses without schema errors.
  • Spec Reachability: Pings remote URLs with configured authentication or verifies local spec file existence, confirming valid HTTP 200 responses and reachable paths.
  • Peer Dependencies: Checks whether your configured validation library (zod, yup, or joi) is installed in node_modules and reports version status.
  • Endpoint Cache: Inspects internal schema store cache integrity to ensure fast subsequent builds.
  • Folder Permissions: Verifies write access to the configured output directory (e.g. ./src/api).

Structured JSON Health Report

When run with --json, doctor outputs a pure JSON object ideal for pre-flight pipeline checks and AI assistants:

json
{
  "healthy": true,
  "checks": [
    { "name": "Configuration", "status": "ok", "message": "Valid openapi.sync.ts found" },
    { "name": "Spec Reachability: petstore", "status": "ok", "message": "HTTP 200 OK (20 endpoints discovered)" },
    { "name": "Peer Dependency: zod", "status": "ok", "message": "zod v3.23.8 installed" },
    { "name": "Output Directory", "status": "ok", "message": "./src/api is writable" }
  ],
  "recommendations": []
}

๐Ÿงน Stale File Purge

As your API evolves, endpoints and data models are frequently renamed or deprecated. Standard code generators leave obsolete files behind, causing dead code and broken imports. openapi-sync maintains a manifest at .openapi-sync/manifest.json to track all generated files, allowing you to safely detect and clean up orphaned files.

bash
# Preview stale files without deleting anything
npx openapi-sync purge --dry-run

# Output preview as machine-readable JSON
npx openapi-sync purge --dry-run --json

# Delete stale files without interactive confirmation (CI & Agent-safe)
npx openapi-sync purge --yes

# Limit stale cleanup to a specific configured API
npx openapi-sync purge --api petstore --yes

๐Ÿ’ก Pro-Tip: Run npx openapi-sync purge --dry-run --json inside your CI pipeline to alert developers when previously generated API files need pruning.

Programmatic Usage

Programmatic API Usage

Duration: 0:10

Use OpenAPI Sync programmatically in your Node.js scripts and build tools.

Watch on YouTube

openapi-sync exports a complete suite of programmatic TypeScript functions for full automation in Node.js, scripts, build tools, and AI agents.

Synchronize & Generate Clients

typescript
import { Init, GenerateClient } from "openapi-sync";

// 1. Sync types, endpoints, and validation schemas
const syncResult = await Init({ silent: true });
if (syncResult.success) {
  console.log("Files written:", syncResult.filesWritten);
  console.log("Endpoints synchronized:", syncResult.endpointCount);
}

// 2. Generate a typed API client programmatically
const clientResult = await GenerateClient({
  type: "react-query", // "fetch" | "axios" | "react-query" | "swr" | "rtk-query"
  silent: true,
});
console.log("Client files written:", clientResult.filesWritten);

Inspect, Query & Validate Without Regenerating

typescript
import {
  ValidateConfig,
  ListEndpoints,
  GetEndpointDetails,
  ReadGeneratedType,
} from "openapi-sync";

// Pre-flight validation (no files written)
const validation = await ValidateConfig({ silent: true });
console.log("Config valid?", validation.valid);

// Search & paginate endpoints
const endpoints = await ListEndpoints({
  apiName: "petstore",
  pathContains: "pet",
  limit: 10,
  offset: 0,
  silent: true,
});
console.log("Found endpoints:", endpoints.petstore);

// Deep inspection of a single endpoint
const detail = await GetEndpointDetails({
  apiName: "petstore",
  operationId: "getPetById",
  silent: true,
});
console.log("Method:", detail.endpoint.method);
console.log("Parameters:", detail.endpoint.parameters);

// Read exact generated TypeScript interface
const typeDecl = await ReadGeneratedType({
  apiName: "petstore",
  typeName: "Pet",
  silent: true,
});
console.log(typeDecl);

Diagnostic Health Checks & Stale Cleanup

typescript
import { Doctor, Purge } from "openapi-sync";

// 1. Run diagnostic health checks
const report = await Doctor({ silent: true });
console.log("System healthy?", report.healthy);
if (!report.healthy) {
  console.warn("Recommendations:", report.recommendations);
}

// 2. Detect and purge stale generated files
const purgeReport = await Purge({ yes: true, silent: true });
console.log("Removed stale files:", purgeReport.purged);

AI Agent Integration (MCP)

OpenAPI Sync includes a full-featured Model Context Protocol (MCP) server. Instead of pasting massive 5MBโ€“15MB Swagger or OpenAPI specifications into an AI prompt โ€” which blows past token limits and induces hallucinations โ€” coding assistants (Cursor, Claude Desktop, Windsurf, Zed, and custom AI agents) connect directly to OpenAPI Sync over stdio to query only the exact endpoints, schemas, and types they need.

๐Ÿค– Two ways to install: You can spin up the MCP server directly via the dedicated zero-install npm package npx openapi-sync-mcp, or run it through your project's main CLI via npx openapi-sync mcp.

4 Ways Humans & Agents Access OpenAPI Sync

Depending on whether your workflow runs through an IDE chat window, an autonomous agent in a terminal, or custom automation scripts, OpenAPI Sync offers 4 native access methods:

๐Ÿ“ฆ

1. Dedicated MCP Package

Zero project install required. Point your Cursor or Claude Desktop config directly to npm and start querying API tools instantly.

bash
npx -y openapi-sync-mcp
โšก

2. Main CLI MCP Command

If openapi-sync is already in your repository's devDependencies or global PATH, run the built-in MCP command directly.

bash
npx openapi-sync mcp
๐Ÿค–

3. Agent-Safe CLI (--json)

For autonomous agents with bash/terminal access (Cursor Agent, Claude Code, Antigravity). Runs 100% non-interactively with structured JSON envelopes.

bash
npx openapi-sync list-endpoints --json
๐Ÿงฉ

4. Programmatic Node / ESM API

Import the runtime directly in TypeScript/Node scripts, CI pipelines, or internal developer portals for seamless workflow automation.

typescript
import { ValidateConfig, Init } from "openapi-sync";
// Or spawn the stdio server:
import "openapi-sync/mcp";

Host Configuration Guides

1. Setup for Cursor

Create or update .cursor/mcp.json in your project root to enable project-scoped tools:

json
{
  "mcpServers": {
    "openapi-sync": {
      "command": "npx",
      "args": ["-y", "openapi-sync-mcp"],
      "cwd": "${workspaceFolder}"
    }
  }
}

Tip: You can also add it globally via Cursor Settings โ†’ Features โ†’ MCP โ†’ + Add New MCP Server with command npx -y openapi-sync-mcp.

2. Setup for Claude Desktop

Add the following to your Claude Desktop configuration file at ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\\Claude\\claude_desktop_config.json (Windows):

json
{
  "mcpServers": {
    "openapi-sync": {
      "command": "npx",
      "args": ["-y", "openapi-sync-mcp"],
      "cwd": "/path/to/your/project"
    }
  }
}

3. Setup for Windsurf (Codeium)

Add the server entry to ~/.codeium/windsurf/mcp_config.json:

json
{
  "mcpServers": {
    "openapi-sync": {
      "command": "npx",
      "args": ["-y", "openapi-sync-mcp"]
    }
  }
}

4. Setup for Zed

Add the server to your Zed settings.json under context_servers:

json
{
  "context_servers": [
    {
      "name": "openapi-sync",
      "command": {
        "path": "npx",
        "args": ["-y", "openapi-sync-mcp"]
      }
    }
  ]
}

5. Setup for Google Antigravity

Add the server to your global Antigravity configuration (~/.gemini/config/mcp_config.json) or your project root (.agents/mcp_config.json):

json
{
  "mcpServers": {
    "openapi-sync": {
      "command": "npx",
      "args": ["-y", "openapi-sync-mcp"]
    }
  }
}

All 10 Available MCP Tools

When connected, your AI assistant receives immediate access to these 10 structured tools:

Tool NameDescription & Key Arguments
openapi_sync_read_configRead and parse current openapi.sync configuration without executing sync
openapi_sync_initCreate a new config file non-interactively with auth, preset, and runSync flags
openapi_sync_validateValidate config and specs without writing files (supports auth and overrides)
openapi_sync_doctorRun diagnostic health checks on config, specs, peer dependencies, and permissions
openapi_sync_list_endpointsList discovered endpoints with tags, pagination, path filtering, and cache reuse
openapi_sync_get_endpoint_detailsInspect full parameters, request bodies, and response types by operationId or name
openapi_sync_read_generated_typeRead the exact generated TypeScript interface or type declaration (supports pagination)
openapi_sync_syncExecute full synchronization โ€” generates TypeScript types, endpoints, and validation schemas
openapi_sync_generate_clientGenerate typed client (fetch, next-fetch, axios, react-query, swr, rtk-query)
openapi_sync_purgeDetect and purge stale generated files from previous API specs (supports dryRun and yes)

Typical Agent Multi-Turn Workflow

Once the MCP server is configured in Cursor or Claude, you can prompt the agent naturally:

bash
# Prompt in Cursor Agent or Claude Desktop:
"We need to implement the billing page. Use openapi-sync to find all subscription-related endpoints, inspect the checkout session schema, and generate a React Query client."

# Autonomous Multi-Turn Execution Flow:
# 1. Calls 'openapi_sync_read_config' to check configured API sources
# 2. Calls 'openapi_sync_list_endpoints' with pathContains: "subscription"
# 3. Calls 'openapi_sync_get_endpoint_details' for operationId "createCheckoutSession"
# 4. Calls 'openapi_sync_read_generated_type' for "CreateCheckoutSessionDTO"
# 5. Calls 'openapi_sync_generate_client' with type: "react-query"
# 6. Builds the frontend UI using the exact generated types and hooks!

๐ŸŒ External Marketplaces & Registries

The openapi-sync-mcp server is registered, indexed, and installable across all major Model Context Protocol marketplaces and registries:

โšก Cursor Directory1-Click Install

The premier hub for Cursor rules and MCP extensions. Deep link opens Cursor and configures the server automatically.

Browse Cursor Directory โ†’
๐Ÿ›ก๏ธ Glama.aiSchema Verified

Production-grade MCP server catalog with verified maintainership and tool schema introspection.

Verified via glama.json
Explore on Glama.ai โ†’
๐Ÿ“ฆ npm RegistryOfficial

The official standalone npm package providing the zero-install executable runtime.

npx openapi-sync-mcp
View on npm โ†’
๐Ÿช Antigravity & MCP StoreOfficial Registry

Indexed in the official Model Context Protocol Registry and discoverable across Antigravity IDE and compatible clients.

io.github.akintomiwa-fisayo/openapi-sync-mcp
View MCP Registry โ†’

โš ๏ธ Error Code Reference

Every error emitted by openapi-sync belongs to a typed subclass of OpenApiSyncError with a stable machine-readable code string. Whether parsing CLI JSON output or handling errors in TypeScript, applications and AI agents can deterministically branch on error types:

Error CodeError ClassDescription & Suggested Remediation
CONFIG_NOT_FOUNDConfigNotFoundErrorNo openapi.sync config file found in cwd. Run `npx openapi-sync init -y` or pass `--api-url`.
CONFIG_PARSE_FAILEDConfigParseErrorConfiguration file failed to evaluate or parse. Verify TypeScript syntax or ensure referenced environment variables exist.
CONFIG_INVALIDConfigValidationErrorConfiguration contains invalid or missing required properties (e.g. empty `api` map).
SPEC_FETCH_FAILEDSpecFetchErrorNetwork error, DNS failure, or HTTP 401/403/404 response. Verify URL or supply credentials via `--auth-type`.
SPEC_READ_FAILEDSpecReadErrorLocal OpenAPI specification file could not be found or read. Check relative file path in configuration.
SPEC_PARSE_FAILEDSpecParseErrorSpecification is not a valid OpenAPI 3.x or Swagger 2.0 document. Verify syntax with Swagger Editor.
GENERATION_FAILEDGenerationErrorFailed to write generated files to disk. Ensure the destination directory has write permissions.
UNKNOWN_APIUnknownApiErrorTarget API specified via `--api <name>` was not found in your configuration file.

Troubleshooting

Common Issues & Troubleshooting

Duration: 0:10

Learn how to debug and resolve common issues when using OpenAPI Sync.

Watch on YouTube

Configuration File Not Found

Error: No config found

Solution: Ensure you have one of these files in your project root:openapi.sync.json, openapi.sync.ts, or openapi.sync.js

Network Timeout Errors

Error: timeout of 60000ms exceeded

Solution: The tool includes automatic retry with exponential backoff. Check your internet connection and verify the OpenAPI spec URL is accessible.

TypeScript Compilation Errors

Error: Cannot find module './src/api/petstore/types'

Solution: Ensure the sync process completed successfully and check that the folder path in config is correct.

macOS Big Sur (11.x) - esbuild Installation Error

Error: dyld: Symbol not found: _SecTrustCopyCertificateChain

Cause: The default esbuild version requires macOS 12.0+ APIs that aren't available in Big Sur (darwin 20.x).

Solution 1: Install compatible esbuild first:

bash
# Install compatible esbuild first
npm install esbuild@0.17.19

# Then install openapi-sync
npm install openapi-sync

Solution 2: Add an override to your package.json:

json
{
  "overrides": {
    "esbuild": "0.17.19"
  }
}

Note: This issue only affects macOS Big Sur. Users on macOS 12+ are not affected and will get the latest esbuild version automatically.

API Reference

Init(options?: InitOptions)

Initializes OpenAPI sync with the specified configuration.

typescript
import { Init } from "openapi-sync";

await Init({ 
  refetchInterval: 10000 
});

Exported Types

typescript
import {
  IConfig,
  IOpenApiSpec,
  IOpenApSchemaSpec,
  IConfigReplaceWord,
  IConfigExclude,
  IConfigInclude,
  IConfigDoc
} from "openapi-sync/types";

Changelog

Track the evolution of OpenAPI Sync with detailed release notes and version history.

v6.4.2

LATEST2026-09-17

add official Model Context Protocol Registry verification with mcpName declaration

  • streamline MCP marketplace integrations and documentation across Cursor Directory, Glama, and Antigravity
  • remove unpublished registries and add direct deep-link 1-click install support

v6.4.1

2026-09-17

publish official standalone openapi-sync-mcp package on npm for zero-install agent workflows

v6.4.0

2026-09-12

default output folder is now project root (""), writing directly to ./<apiName>/ without artificial nesting

v6.3.2

2026-08-17

fix schema duplicate type generation preventing conflicting declarations (e.g. duplicate IPet in OpenAPI 3.0 specs)

v6.3.1

2026-08-17

resolve ESM programmatic import and module syntax issues with tsup shims and __dirname elimination

๐Ÿ“– Full Changelog: For complete release notes and detailed changes, visit the dedicated Changelog page.