JSON to TypeScript DTO — Generate Data Transfer Object Types
- DTO is a pattern from .NET and Java worlds — TypeScript uses interfaces for the same job.
- Generate a DTO shape from a sample JSON payload, then layer on validation decorators if needed.
- Works cleanly with NestJS class-validator or plain interfaces in Express/Fastify.
Table of Contents
The DTO — Data Transfer Object — is a pattern you inherit from .NET, Spring, or Java codebases. In TypeScript it's usually just an interface (or sometimes a class with validation decorators for NestJS). Either way, the shape comes from the API you're integrating with — and generating it from a real JSON sample is faster than writing it by hand.
This guide covers the TypeScript DTO patterns that matter: where interfaces are enough, where classes with decorators earn their keep, and how to generate the starting point from JSON in one paste.
What a DTO Actually Is in a TypeScript Codebase
In C# and Java, a DTO is typically a class with fields and no behavior. Its job is to represent data as it crosses a boundary — API response, message queue payload, database row — separate from the domain model with its business logic.
TypeScript doesn't force you to pick between class and interface. The common convention:
- Interface for plain-data DTOs — types only, zero runtime cost. Use when the DTO just crosses the wire.
- Class with decorators for validated DTOs — NestJS + class-validator is the canonical example. Use when you need runtime validation at the boundary.
Both are legitimate. Both can be derived from the same JSON sample. The generator produces interfaces; converting to a class is a few minutes of adaptation once you've done it a couple times.
Interface DTO — The Common Case
For most TypeScript projects, a plain interface is enough:
// create-user.dto.ts
export interface CreateUserDto {
email: string;
password: string;
displayName: string;
acceptTerms: boolean;
}
Paste the corresponding JSON into the generator:
{
"email": "[email protected]",
"password": "••••••••",
"displayName": "Alex",
"acceptTerms": true
}
You get the interface back. Rename Root to CreateUserDto, drop into your project, done.
This is the fastest path for Express, Fastify, Hono, Koa, or any framework that doesn't mandate a class-based validation system. Runtime validation (Zod, Yup) happens as a separate step — the DTO defines the shape, the validator enforces it.
Sell Custom Apparel — We Handle Printing & Free ShippingNestJS DTOs With class-validator Decorators
NestJS's DTO pattern uses classes with decorator-based validation. The shape comes from the class, the rules from the decorators:
import { IsEmail, IsString, MinLength, IsBoolean } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsString()
@MinLength(1)
displayName: string;
@IsBoolean()
acceptTerms: boolean;
}
Generate the shape with our tool first — paste the JSON, copy the interface. Then convert the interface to a class and layer decorators on each field. The generator saves you the tedious part (typing each field); the decorators are the part that actually requires thought.
NestJS's ValidationPipe then auto-validates every incoming request against the DTO, returning 400 with a clear error message if anything's off.
Response DTOs vs Request DTOs — Why You Want Both
A common mistake: reusing the same DTO for both request and response. They look similar — they describe the same entity — but they're usually not identical.
Request DTO: fields the client sends. No id (server assigns it), no createdAt (server timestamps it), maybe a plaintext password that never appears in responses.
Response DTO: fields the server returns. Includes id, createdAt, never the password, sometimes with a different shape (e.g., returning a full user object where the request sent a userId).
Generate each from the actual JSON that crosses the wire for that direction. Your request type gets populated from what the client posts; your response type from what the server sends back. Two generator runs, two files, and they never have to drift.
Sharing DTOs Between Frontend and Backend
Monorepos and shared-packages setups let you define a DTO once and import it from both sides of the wire. The generator output is plain TypeScript — drop it in a shared package and both sides use the same type.
// packages/shared/src/user.dto.ts
export interface UserDto {
id: number;
email: string;
displayName: string;
createdAt: string;
}
Backend uses it for the response type; frontend imports it for the state shape. A change to the shared DTO surfaces as a compile error on whichever side hasn't been updated yet.
One caveat: for class-based DTOs with decorators, sharing is messier — the frontend doesn't need the validation decorators and shouldn't ship them. Either split shape (interface) from validation (class), or keep DTOs per-side and generate fresh from JSON samples.
Generate Your DTO
Paste sample JSON, get a ready-to-use TypeScript DTO interface.
Open Free JSON to TypeScript GeneratorFrequently Asked Questions
Should I use classes or interfaces for DTOs in TypeScript?
Interfaces by default — zero runtime cost and they compile away. Classes only when you need decorator-based validation (NestJS) or prototype methods.
Do I still need runtime validation if I have a typed DTO?
Yes. Types are erased at compile time. Use Zod, Yup, Valibot, or class-validator to actually check incoming data matches the DTO.
Can one DTO serve both request and response?
Rarely — they usually differ (id, timestamps, password). Generate separate DTOs from the actual request and response JSON.
Does the generator produce NestJS-style class DTOs?
No, it produces interfaces. Convert to a class manually and add decorators — it is a small edit for a big validation win.

