Design APIs
Design your data up front and generate schemas, API specifications, client / server code, docs, and more.
import "@typespec/http";
using Http;
model Store {
name: string;
address: Address;
}
model Address {
street: string;
city: string;
}
@route("/stores")
interface Stores {
list(@query filter: string): Store[];
read(@path id: Store): Store;
}
openapi: 3.0.0
info:
title: (title)
version: 0.0.0
tags: []
paths:
/stores:
get:
operationId: Stores_list
parameters:
- name: filter
in: query
required: true
schema:
type: string
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Store'
/stores/{id}:
get:
operationId: Stores_read
parameters:
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Store'
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Store'
components:
schemas:
Address:
type: object
required:
- street
- city
properties:
street:
type: string
city:
type: string
Store:
type: object
required:
- name
- address
properties:
name:
type: string
address:
$ref: '#/components/schemas/Address'
Why TypeSpec
API-First for developers
With TypeSpec, remove the handwritten files that slow you down, and generate standards-compliant API schemas in seconds.

Lightweight language for defining APIs
Inspired by TypeScript, TypeSpec is a minimal language that helps developers describe API shapes in a familiar way.
Learn about TypeSpec for REST APIs →

Easy integration with your toolchain
Write TypeSpec, emit to various formats and integrate with their ecosystems.
~ /my-project tsp init
? Select a templateEmpty project
> REST API
import "@typespec/http";
using Http;
model Pet {
name: string;
age: int32;
}
model Store {
name: string;
address: Address;
}
model Address {
street: string;
city: string;
}
@route("/pets")
interface Pets {
list(@query filter: string): Pet[];
create(@body pet: Pet): Pet;
read(@path id: string): Pet;
}
@route("/stores")
interface Stores {
list(@query filter: string): Store[];
read(@path id: string): Store;
}
import "./common.tsp";
namespace MyOrg.Accounts;
using MyOrg.Types;
model Account {
id: id;
firstName: string;
lastName: string;
createdAt: utcDateTime;
// Use imported type by name only when using `using`
ssn: ssn;
// Or use the fully qualified name
email: MyOrg.Types.email;
balance: Amount;
}
model Amount {
value: decimal128;
currency: Currency;
}
// Create your own error types by extending the Error type
model AccountError is Error<"duplicate-account" | "invalid-account">;
op createAccount(account: Account): Account;
op charge(accountId: id, amount: Amount): void | AccountError;
extern dec group(target: TypeSpec.Reflection.Model, name: valueof string);
import { DecoratorContext, EmitContext, Model, resolvePath } from "@typespec/compiler";
export async function $onEmit(context: EmitContext) {
const outputDir = resolvePath(context.emitterOutputDir, "hello.txt");
await context.program.host.writeFile(outputDir, "hello world!");
}
const groupKey = Symbol.for("my-library/group");
export function $group(context: DecoratorContext, target: Model, value: string) {
context.program.stateMap(groupKey).set(target, value);
}
Start your TypeSpec journey
Install the TypeSpec CLI or check out the playground to get started.