🌾 OATS - OpenAPI TypeScript Sync
Automatically sync OpenAPI specs to TypeScript clients. No manual steps, just real-time updates.

🚀 Quick Start
npm install -D @tryloop/oats
npx oats init
npx oats start
🎯 What is OATS?
OATS eliminates the manual 6-step workflow of syncing OpenAPI changes:
Wait for backend to regenerate OpenAPI spec
Copy spec to client generator
Run generator
Build client
Link to frontend
Restart frontend
With OATS: Change your API → Everything syncs automatically ✨
📋 Configuration
OATS supports multiple configuration formats:
JSON Configuration
{
"$schema": "node_modules/@tryloop/oats/schema/oats.schema.json",
"services": {
"backend": {
"path": "./backend",
"port": 8000,
"startCommand": "npm run dev",
"apiSpec": {
"path": "/api/openapi.json"
}
},
"client": {
"path": "./api-client",
"packageName": "@myorg/api-client",
"generator": "@hey-api/openapi-ts"
},
"frontend": {
"path": "./frontend",
"port": 3000,
"startCommand": "npm run dev"
}
}
}
TypeScript Configuration
import { defineConfig } from '@tryloop/oats'
export default defineConfig({
services: {
backend: {
path: './backend',
port: 8000,
startCommand: 'npm run dev',
apiSpec: {
path: '/api/openapi.json'
}
},
client: {
path: './api-client',
packageName: '@myorg/api-client',
generator: '@hey-api/openapi-ts'
},
frontend: {
path: './frontend',
port: 3000,
startCommand: 'npm run dev'
}
}
})
Note: TypeScript configs are fully supported. OATS includes esbuild for consistent transpilation across all environments.
JavaScript Configuration
const { defineConfig } = require('@tryloop/oats')
module.exports = defineConfig({
})
🌐 Supported Technologies
Backend Frameworks
Frontend Frameworks
All major frameworks: React, Vue, Angular, Svelte, Next.js, Nuxt, Remix
TypeScript Client Generators
🔧 CLI Commands
oats start | Start all services with auto-sync | --config, --quiet, --init-gen |
oats init | Create configuration interactively | --force, --yes |
oats validate | Validate configuration file | --config |
oats detect | Auto-detect project structure | - |
🎨 Key Features
🔄 Real-time Synchronization
- File watching with intelligent debouncing
- Smart change detection - ignores formatting changes
- Hash-based caching - skip unnecessary regeneration
- Concurrent sync prevention - no duplicate operations
🛠️ Developer Experience
- Auto port management - kills conflicting processes
- Cross-platform support - Windows, macOS, Linux
- Config hot-reload - changes restart services automatically
- IntelliSense support - JSON schema for autocompletion
- Multiple config formats - JSON, JS, or TypeScript (with built-in transpilation)
- Automatic backend URL injection - Frontend uses local API in dev, production in prod
🚀 Performance
- 45% faster sync than manual process
- Incremental builds when possible
- Parallel service startup
- Efficient polling for runtime API specs
📚 Examples
Python FastAPI + React
{
"services": {
"backend": {
"path": "../backend",
"port": 8000,
"runtime": "python",
"python": {
"virtualEnv": ".venv"
},
"startCommand": ".venv/bin/uvicorn main:app --reload",
"apiSpec": {
"path": "/openapi.json"
}
},
"client": {
"path": "../api-client",
"packageName": "@myapp/api",
"generator": "@hey-api/openapi-ts"
},
"frontend": {
"path": "./",
"port": 3000,
"startCommand": "npm start"
}
}
}
NestJS + Next.js Monorepo
{
"services": {
"backend": {
"path": "./apps/api",
"port": 3333,
"startCommand": "nx serve api",
"apiSpec": {
"path": "swagger.json"
}
},
"client": {
"path": "./packages/api-client",
"packageName": "@myapp/api-client",
"generator": "custom",
"generateCommand": "yarn openapi-ts"
},
"frontend": {
"path": "./apps/web",
"port": 4200,
"startCommand": "nx serve web"
}
}
}
📖 Configuration Reference
Service Configuration
path | Path to service directory | ✅ |
port | Port number (backend/frontend) | ⚠️ |
startCommand | Command to start service | ✅ |
runtime | "node" or "python" | ❌ |
apiSpec.path | Path to OpenAPI spec | ✅ |
⚠️ Port is required for backend/frontend services, but not for client
Sync Options
strategy | "smart" | "smart" or "aggressive" |
debounceMs | 1000 | Delay before regenerating |
autoLink | true | Auto-link packages |
pollingInterval | 5000 | For runtime API specs |
Log Options
level | "info" | "debug", "info", "warn", "error" |
colors | true | Enable colored output |
timestamps | false | Show timestamps in logs |
showServiceOutput | true | Display output from services |
🛡️ Troubleshooting
Port conflicts
OATS automatically handles port conflicts. To disable:
{
"services": {
"backend": {
"env": {
"OATS_AUTO_KILL_PORTS": "false"
}
}
}
}
Client not updating
- Check package is linked:
npm ls @myorg/api-client
- For Vite: Exclude from optimization in
vite.config.ts
- Ensure
packageName matches your client's package.json
Automatic Backend URL Injection
OATS automatically injects your backend URL into your frontend environment:
const API_URL = import.meta.env.VITE_OATS_BACKEND_BASE_URL || 'https://api.production.com'
How it works:
- OATS detects your frontend framework (Vite, CRA, Next.js, etc.)
- Injects the backend URL with the correct prefix:
- Vite:
VITE_OATS_BACKEND_BASE_URL
- Create React App:
REACT_APP_OATS_BACKEND_BASE_URL
- Next.js:
NEXT_PUBLIC_OATS_BACKEND_BASE_URL
- Vue CLI:
VUE_APP_OATS_BACKEND_BASE_URL
- Your app uses local backend when running with OATS, production otherwise
No configuration needed - it just works!
TypeScript config issues
OATS fully supports TypeScript configs (.ts files) with built-in transpilation:
- Configs work consistently across all environments
- No additional setup or dependencies required
- Use ESM syntax:
export default defineConfig({...})
Command not found
Use npx or add to scripts:
{
"scripts": {
"dev:sync": "oats start"
}
}
🤝 Contributing
Contributions welcome! See CONTRIBUTING.md for details.
git clone https://github.com/loopkitchen/oats.git
yarn install
yarn test
yarn dev
📄 License
MIT © Hari Shekhar
GitHub •
npm •
Issues