
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
micro-contracts
Advanced tools
Contract-first OpenAPI toolchain that keeps TypeScript UI and microservices aligned via code generation
Contract-first vertical slices for TypeScript Web/API systems.
micro-contracts is a contract-first toolchain for TypeScript Web/API development. It tackles common failure modes—frontend/backend contract drift, duplicated "common" rules, and accidental breaking changes in public APIs—by treating OpenAPI as the Single Source of Truth (SSoT).
Contracts alone aren't enough—they must be enforceable. micro-contracts includes Enforceable Guardrails that prevent both humans and AI from bypassing the contract-first workflow: blocking direct edits to generated files, detecting drift, and verifying security declarations match implementations.
The core architecture is organized along two axes:
| Axis | Description | Example |
|---|---|---|
| Vertical (feature-aligned slices) | A module is a feature-aligned contract boundary. The same contract spans UI (frontend) and API (backend). | core, billing, users |
| Horizontal (cross-cutting concerns) | Auth, tenancy, rate limiting, and shared error behavior are applied consistently via OpenAPI Overlays. | x-middleware: [requireAuth, tenantIsolation] |
| # | Differentiator | What it means |
|---|---|---|
| 1 | Vertical Modules + Horizontal Overlays | Feature-aligned modules as contract boundaries; cross-cutting concerns (auth, rate-limit) injected via OpenAPI Overlays. |
| 2 | OpenAPI as SSoT → Multi-artifact generation | Single spec generates contract packages, server routes, and frontend clients. No manual sync required. |
| 3 | Enforceable Guardrails | Built-in checks prevent bypassing contract-first workflow—blocks direct edits to generated files, detects drift, verifies security declarations. See Guardrails. |
| 4 | Public Surface Governance | contract-published is extracted (not duplicated) from the master contract. x-micro-contracts-non-exportable fails generation if internal data leaks. |
| 5 | Explicit Module Dependencies | x-micro-contracts-depend-on declares cross-module dependencies. deps/ re-exports only declared types; enables impact analysis. |
| 6 | Screen Spec | Declare frontend screen contracts (ViewModel, navigation, analytics events) in OpenAPI. One YAML drives typed navigation maps and event hooks. See Screen Spec. |
| Scenario | Why micro-contracts helps |
|---|---|
| Modular monolith → microservices | Same contracts work in monolith or split services; dependency tracking prevents hidden coupling |
| Multiple teams sharing OpenAPI | Explicit module dependencies make cross-team impact visible |
| Published API with compatibility SLA | contract-published extraction + x-micro-contracts-non-exportable fail-fast prevents accidental exposure |
| Cross-cutting concerns at scale | OpenAPI Overlays inject auth/rate-limit/tenancy and extension properties without copy-paste |
Not the best fit for: Single-developer projects, auto-generated UI from schema, multi-language SDK generation (use OpenAPI Generator instead).
Prerequisites: Node.js 18+, TypeScript 5.0+, ESM (
"type": "module").
# 1. Install
npm install --save-dev micro-contracts
# 2. Initialize module structure
npx micro-contracts init core --openapi path/to/your/spec.yaml
# 3. Generate all code
npx micro-contracts generate
// 4. Use in your server
import { registerRoutes } from './core/routes.generated.js';
await registerRoutes(fastify);
What
initcreates: Theinitcommand creates starter templates for Fastify (server) and fetch API (client). These are scaffolds to get you started — modify them for your framework (Express, Hono, Axios, etc.) or add new output types.📦 Full working example: See
examples/for a complete project with multiple modules, overlays, and cross-module dependencies.
OpenAPI spec (spec/{module}/openapi/*.yaml)
↓ micro-contracts generate
Contract packages (packages/contract/{module}/)
├── schemas/types.ts # Request/Response types
├── services/ # Service interfaces
└── overlays/ # Overlay handler interfaces
↓
Server routes + Frontend clients (generated via templates)
| Concept | Definition | Example |
|---|---|---|
| Module | Logical contract boundary (OpenAPI + Service) | core, billing, users |
| Service | Deployment unit (can contain 1+ modules) | api-server |
A monolith may have multiple modules in one service. Start with multiple modules in one service and split later as needed.
| Package | Description | Compatibility Policy |
|---|---|---|
contract | Master contract (all APIs) | Internal APIs can change freely |
contract-published | Public APIs only (x-micro-contracts-published: true) | Must maintain backward compatibility |
Key insight: contract-published is extracted from contract (not generated separately). This ensures a single SSoT.
x-middleware (or custom extensions) in OpenAPIopenapi.generated.yaml📖 Deep Dive: See OpenAPI Overlays (Deep Dive) for complete examples and configuration.
Standard OpenAPI constructs can also define frontend screen contracts — bridging the API layer and UI components. A single YAML file drives ViewModel types, typed navigation maps, and analytics event hooks.
Screen Spec (OpenAPI YAML)
├── ViewModel Types (from schemas — zero new template work)
├── Navigation Map (from response links → typed routing)
└── Event Hooks (from x-events → typed analytics)
Enable with screen: true in module config:
modules:
myScreens:
openapi: spec/screens/screens.yaml
screen: true
outputs:
screen-navigation:
output: frontend/src/screens/navigation.generated.ts
template: screen-navigation.hbs
screen-events:
output: frontend/src/screens/events.generated.ts
template: screen-events.hbs
Initialize a screen module with starter files:
npx micro-contracts init myScreens --screens
📖 Deep Dive: See Screen Spec for the full guide — YAML structure,
x-screen-*extensions,TemplateContext.screens, lint rules, and custom template examples.
project/
├── spec/ # ✅ Human-edited (contract source of truth)
│ ├── spectral.yaml # Global lint rules
│ ├── default/templates/ # Handlebars templates (customizable)
│ ├── _shared/
│ │ ├── openapi/ # Shared schemas (ProblemDetails, etc.)
│ │ └── overlays/ # Cross-module overlays
│ └── {module}/
│ ├── openapi/{module}.yaml # OpenAPI spec
│ └── overlays/ # Module-specific overlays
│
├── packages/ # ❌ Auto-generated (DO NOT EDIT)
│ ├── contract/{module}/
│ │ ├── schemas/ # Types, validators
│ │ ├── services/ # Service interfaces
│ │ ├── overlays/ # Overlay handler interfaces
│ │ └── deps/ # Re-exports from dependencies
│ └── contract-published/{module}/ # Public API subset
│
├── server/src/{module}/
│ ├── routes.generated.ts # ❌ Auto-generated (template: fastify-routes.hbs)
│ ├── services/ # ✅ Human-edited (service implementations)
│ └── overlays/ # ✅ Human-edited (overlay implementations)
│
└── frontend/src/{module}/
└── api.generated.ts # ❌ Auto-generated (template: fetch-client.hbs)
Note:
*.generated.tsfiles are generated from Handlebars templates inspec/default/templates/. You can customize or replace templates for different frameworks (Express, Hono, Axios, etc.).Why commit generated files? Generated artifacts are committed to enable code review of contract changes and CI drift detection. If spec changes but generated code doesn't match, CI fails.
| Extension | Type | Description |
|---|---|---|
x-micro-contracts-service | string | Service class name (e.g., User, Order) |
x-micro-contracts-method | string | Method name to call (should match operationId) |
| Extension | Type | Description |
|---|---|---|
x-micro-contracts-published | boolean | Include in contract-published (compatibility SLA) |
x-micro-contracts-non-exportable | boolean | Mark as non-exportable (fails if used in published endpoints) |
x-micro-contracts-depend-on | string[] | Explicit dependencies on other modules' published APIs |
Used in modules with screen: true. See Screen Spec for details.
| Extension | Type | Description |
|---|---|---|
x-screen-const | string | Stable constant name (e.g., HOME) |
x-screen-id | string | Traceability ID (e.g., SCR-001) |
x-screen-name | string | Generated symbol name (e.g., HomePage) |
x-back-navigation | boolean | Supports history-based back navigation |
x-events | array | Analytics event declarations ({name, type, method, params?}) |
paths:
/api/users:
get:
operationId: getUsers
x-micro-contracts-service: User
x-micro-contracts-method: getUsers
x-micro-contracts-published: true
x-middleware: [requireAuth] # Custom extension for overlays
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/UserListResponse'
Declare dependencies with x-micro-contracts-depend-on:
# spec/billing/openapi/billing.yaml
info:
x-micro-contracts-depend-on:
- core.User.getUsers
- core.User.getUserById
Import via generated deps/:
// ✅ Recommended: Import from deps/
import type { User } from '@project/contract/billing/deps/core';
// ❌ Avoid: Direct contract-published import
import type { User } from '@project/contract-published/core/schemas';
Create micro-contracts.config.yaml. All paths support {module} placeholder.
| Key | Type | Required | Description |
|---|---|---|---|
contract.output | string | yes | Output directory for contract packages |
contract.serviceTemplate | string | no | Custom Handlebars template for service interface generation |
contractPublic.output | string | yes | Output directory for public contract packages |
outputs.<id>.output | string | yes | Output file path |
outputs.<id>.template | string | yes | Handlebars template file path |
outputs.<id>.overwrite | boolean | no | Overwrite existing files (default: true) |
outputs.<id>.condition | string | no | hasPublicEndpoints | hasOverlays | always (default: always) |
outputs.<id>.enabled | boolean | no | Enable/disable this output (default: true) |
outputs.<id>.config | object | no | Template-specific configuration passed to context |
overlays.shared | string[] | no | Overlay files applied to all modules |
overlays.collision | string | no | error | warn | last-wins (default: error) |
docs.enabled | boolean | no | Enable documentation generation (default: true) |
docs.template | string | no | Documentation template |
sharedModuleName | string | no | Shared module name for overlays |
| Key | Type | Required | Description |
|---|---|---|---|
openapi | string | yes | Path to OpenAPI spec file |
screen | boolean | no | Enable screen spec mode (x-screen-* extensions, TemplateContext.screens) |
contract.output | string | no | Override contract output directory |
contract.serviceTemplate | string | no | Override custom service interface template |
contractPublic.output | string | no | Override public contract output directory |
outputs.<id>.enabled | boolean | no | Enable/disable specific output for this module |
outputs.<id>.* | — | no | Override any output config field |
overlays | string[] | no | Module-specific overlay files |
dependsOn | string[] | no | Dependencies ({module}.{service}.{method}) |
spectral | string | no | Module-specific Spectral config path |
docs.enabled | boolean | no | Override documentation generation |
defaults:
contract:
output: packages/contract/{module}
contractPublic:
output: packages/contract-published/{module}
outputs:
server-routes:
output: server/src/{module}/routes.generated.ts
template: spec/default/templates/fastify-routes.hbs
frontend-api:
output: frontend/src/{module}/api.generated.ts
template: spec/default/templates/fetch-client.hbs
overlays:
shared:
- spec/_shared/overlays/middleware.overlay.yaml
modules:
core:
openapi: openapi/core.yaml
billing:
openapi: openapi/billing.yaml
dependsOn:
- core.User.getUsers
outputs:
frontend-api:
enabled: false
Generate code from OpenAPI specifications.
| Option | Description |
|---|---|
-c, --config <path> | Path to config file |
-m, --module <names> | Module names, comma-separated (default: all) |
--contracts-only | Generate contract packages only |
--server-only | Generate server routes only |
--frontend-only | Generate frontend clients only |
--docs-only | Generate documentation only |
--skip-lint | Skip linting before generation |
--no-manifest | Skip manifest generation |
--manifest-dir <path> | Directory for manifest (default: packages/) |
--force | Bypass input hash cache and always regenerate |
--no-cache | Run without reading or writing input hash cache |
Initialize a new module structure with starter templates.
| Option | Description |
|---|---|
-d, --dir <path> | Base directory (default: src) |
-i, --openapi <path> | OpenAPI spec to process (auto-adds extensions) |
-o, --output <path> | Output path for processed OpenAPI |
--skip-templates | Skip creating starter templates |
--screens | Initialize as screen spec module (generates screen templates and starter spec) |
Lint OpenAPI specification.
| Option | Description |
|---|---|
--strict | Treat warnings as errors |
Run guardrail checks.
| Option | Description |
|---|---|
--only <checks> | Run only specific checks (comma-separated) |
--skip <checks> | Skip specific checks (comma-separated) |
--gate <gates> | Run checks for specific gates only (1-5) |
-v, --verbose | Enable verbose output |
--fix | Auto-fix issues where possible |
-g, --guardrails <path> | Path to guardrails.yaml |
-d, --generated-dir <path> | Path to generated files directory (default: packages/) |
--changed-files <path> | Path to file containing changed files (for CI) |
--list | List available checks |
--list-gates | List available gates |
Run full guardrails pipeline: Gate 1,2 → Generate → Gate 3,4,5.
| Option | Description |
|---|---|
-c, --config <path> | Path to config file |
-v, --verbose | Enable verbose output |
--skip <checks> | Skip specific checks (comma-separated) |
--continue-on-error | Continue running even if a step fails |
-g, --guardrails <path> | Path to guardrails.yaml |
-d, --generated-dir <path> | Path to generated files directory (default: packages/) |
--no-manifest | Skip manifest generation |
--skip-lint | Skip linting before generation |
--contracts-only | Generate contract packages only |
--server-only | Generate server routes only |
--frontend-only | Generate frontend clients only |
--docs-only | Generate documentation only |
--force | Bypass input hash cache and always regenerate |
--no-cache | Run without reading or writing input hash cache |
See Enforceable Guardrails for gate details and CI configuration.
Analyze module dependencies.
| Option | Description |
|---|---|
-c, --config <path> | Path to config file |
-m, --module <name> | Module to analyze |
--graph | Output dependency graph (Mermaid) |
--impact <ref> | Analyze impact of changing a specific API |
--who-depends-on <ref> | Find modules that depend on a specific API |
--validate | Validate dependencies against OpenAPI declarations |
Create a guardrails.yaml configuration file.
| Option | Description |
|---|---|
-o, --output <path> | Output path (default: guardrails.yaml) |
Generate or verify manifest for generated artifacts.
| Option | Description |
|---|---|
-d, --dir <path> | Directory to scan (default: packages/) |
--verify | Verify existing manifest |
-o, --output <path> | Output manifest path |
// packages/contract/core/services/UserServiceApi.ts
export interface UserServiceApi {
getUsers(input: UserService_getUsersInput): Promise<UserListResponse>;
getUserById(input: UserService_getUserByIdInput): Promise<User>;
}
// server/src/core/services/UserService.ts
import type { UserServiceApi } from '@project/contract/core/services/UserServiceApi.js';
export class UserService implements UserServiceApi {
async getUsers(input) {
// Input is HTTP-agnostic: { limit?: number, offset?: number }
return { users: [...], total: 100 };
}
}
| Document | Description |
|---|---|
| Examples | Complete working project with multiple modules, overlays, and cross-module dependencies |
| Screen Spec | Frontend screen contracts — ViewModel, navigation, analytics events in OpenAPI |
| OpenAPI Overlays (Deep Dive) | Complete overlay examples, JSONPath patterns, template context |
| Enforceable Guardrails (AI-ready) | CI integration, security checks, allowlist configuration |
| Aspect | micro-contracts | OpenAPI Generator | ts-rest |
|---|---|---|---|
| Primary focus | Contract governance (server + frontend + CI) | Multi-language SDK generation | TypeScript-first contract |
| SSoT | OpenAPI | OpenAPI | TypeScript |
| Multi-artifact generation | ✅ contract + routes + clients | △ SDK-focused (different goal) | ✅ Strong client/server alignment |
| Enforceable guardrails | ✅ Built-in (drift, no direct edit, CI gates) | ❌ Requires separate design | ❌ Requires separate design |
| Public API governance | ✅ contract-published + fail-fast | ❌ Manual | ❌ N/A |
| Module dependencies | ✅ x-micro-contracts-depend-on + deps/ | ❌ Manual | ❌ Manual |
| Cross-cutting concerns | ✅ OpenAPI Overlays | ❌ Manual | △ Code-level implementation |
MIT
FAQs
Contract-first OpenAPI toolchain that keeps TypeScript UI and microservices aligned via code generation
We found that micro-contracts demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.