Documentation
JSON, CSV, OpenAPI, GraphQL → TypeScript interfaces or Zod schemas. In one command.
Installation
npm install -D snaptypeRequires Node.js 20+. ESM only.
Quick start
# TypeScript interfaces from a JSON file
snaptype from-json users.json -o src/types/user.ts
# Zod schema from a REST API response
snaptype from-url https://api.example.com/users -o src/schemas/user.ts --zod
# Both TypeScript and Zod at once
snaptype from-json data.json --zod --ts -o src/types.tsfrom-json
Generate TypeScript types or Zod schemas from one or more JSON files.
snaptype from-json <file> [options]Examples
# Single file
snaptype from-json data.json -o src/types/data.ts
# Override the root type name
snaptype from-json response.json --name ApiResponse -o src/types.ts
# Zod schema output
snaptype from-json data.json --zod -o src/schemas/data.ts
# Both TypeScript and Zod
snaptype from-json data.json --zod --ts -o src/types.ts
# Multiple files — merged into one unified type (Pro)
snaptype from-json sample1.json sample2.json sample3.json -o src/types.tsOptions
| Flag | Description |
|---|---|
--name <name> | Override the root type name |
--watch | Regenerate automatically when the file changes (Pro) |
When multiple JSON files are provided (Pro), snaptype merges all samples into a single schema. Fields that appear in some samples but not all become optional, giving you the most accurate type when a real-world API returns slightly different shapes across calls.
from-url
Fetch JSON from one or more HTTP(S) URLs and generate types.
snaptype from-url <url> [options]Examples
# From a REST API
snaptype from-url https://api.github.com/users/octocat -o src/github.ts
# Custom root name
snaptype from-url https://api.example.com/me --name CurrentUser -o src/me.ts
# With authentication header
snaptype from-url https://api.example.com/me \
-H "Authorization: Bearer $TOKEN" \
-o src/me.ts
# Multiple endpoints merged — absent fields become optional (Pro)
snaptype from-url https://api.example.com/users/1 \
https://api.example.com/users/2 \
-o src/user.tsOptions
| Flag | Description |
|---|---|
--name <name> | Override the root type name |
-H, --header <header> | HTTP header, repeatable. Format: "Name: Value" |
--watch | Re-fetch and regenerate on a schedule (Pro) |
Passing multiple URLs requires a Pro licence. Same merge rules as multi-file JSON: absent fields become optional, type conflicts fall back to string.
from-csv
Generate types from the columns of a CSV file. Column headers become property names. Types are inferred from the values in each column. Semantic hints (email, URL, ISO date) are applied automatically.
snaptype from-csv <file> [options]Examples
# TypeScript interfaces from CSV
snaptype from-csv data.csv -o src/types/row.ts
# Snake case property names
snaptype from-csv data.csv --naming snake -o src/types/row.ts
# File without a header row — provide column names manually
snaptype from-csv data.csv \
--columns id,name,score,active \
-o src/types/row.ts
# Watch mode — regenerates on every file save (Pro)
snaptype from-csv data.csv --watch -o src/types/row.tsOptions
| Flag | Description |
|---|---|
--columns <col1,col2,...> | Column names when the file has no header row |
--watch | Re-run on file change (Pro) |
Nullable fields
Empty cells are normalized to null and mark the field as nullable. A column where at least one row is empty becomes string | null (or the equivalent inferred type).
from-stdin
Read JSON from standard input (pipe) and generate types. --name is required because there is no filename to derive the type name from.
snaptype from-stdin --name <TypeName> [options]Examples
# Pipe from curl
curl https://api.example.com/me | snaptype from-stdin --name CurrentUser
# Pipe from another command
cat response.json | snaptype from-stdin --name ApiResponse -o src/types.ts
# With Zod output
curl https://api.example.com/products | snaptype from-stdin --name Product --zodOptions
| Flag | Description |
|---|---|
--name <name> | Required. Root type name |
from-openapi
Parse an OpenAPI 3.x specification (YAML or JSON, local file or URL) and generate types for all schemas. By default, one file is generated per schema — provide a directory as output. Use --single-file to combine all schemas into a single file.
snaptype from-openapi <source> [options]Examples
# One file per schema (default) — output must be a directory
snaptype from-openapi ./openapi.yaml -o ./src/types/
# All schemas in a single file
snaptype from-openapi ./openapi.yaml --single-file -o ./src/api-types.ts
# Remote spec
snaptype from-openapi https://petstore3.swagger.io/api/v3/openapi.json -o ./types/
# With Zod schemas
snaptype from-openapi ./openapi.yaml --zod -o ./src/schemas/Options
| Flag | Description |
|---|---|
--single-file | Output all schemas into one file instead of one file per schema |
What gets generated
- Request/response body schemas
- Reusable component schemas (#/components/schemas/*)
- oneOf / anyOf → TypeScript union types
- allOf → merged flat object
from-graphql Pro
Generate TypeScript interfaces or Zod schemas from a live GraphQL API. Requires SNAPTYPE_LICENSE_KEY to be set.
snaptype from-graphql <endpoint> [options]How it works
The CLI does not run the introspection locally. It sends the endpoint, headers, and generation options to the snaptype server (api.snaptype.dev), authenticated with your licence key. The server runs the introspection, maps the schema, generates the files, and returns their contents. One file is written per user-defined type in the output directory. Deprecated fields and built-in introspection types (__ prefix) are excluded.
Examples
# Public endpoint
snaptype from-graphql https://api.example.com/graphql -o src/graphql-types/
# With authentication header
snaptype from-graphql https://api.example.com/graphql \
-H "Authorization: Bearer $TOKEN" \
-o src/graphql-types/Options
| Flag | Description |
|---|---|
-H, --header <header> | HTTP header forwarded to the GraphQL endpoint. Repeatable. Format: "Name: Value" |
Type mapping
| GraphQL type | Output |
|---|---|
String, ID | string |
Int, Float | number |
Boolean | boolean |
Custom scalar | unknown |
OBJECT, INPUT_OBJECT | interface with fields |
ENUM | type Foo = "A" | "B" |
UNION, INTERFACE | type Foo = A | B | C |
NON_NULL wrapper | field is not optional, not nullable |
LIST wrapper | field: ItemType[] |
barrel
Generate an index.ts file that re-exports every .ts file in a directory.
snaptype barrel <dir> [options]Examples
# Default: outputs <dir>/index.ts
snaptype barrel ./src/types
# Custom output path
snaptype barrel ./src/types -o src/types/index.ts
# Watch mode — regenerates when files are added or removed
snaptype barrel ./src/types --watchGenerated output
// Generated by snaptype — do not edit manually
export * from './user.js';
export * from './post.js';
export * from './product.js';Options
| Flag | Description |
|---|---|
-o, --output <file> | Output path (default: <dir>/index.ts) |
--watch | Regenerate when .ts files are added or removed |
diff Pro
Detect breaking changes between two snaptype-generated TypeScript files.
snaptype diff <old> <new> [options]Examples
# Compare two versions
snaptype diff types-v1.ts types-v2.ts
# CI mode — exits with code 1 if breaking changes are found
snaptype diff old-types.ts new-types.ts --ciOutput format
Breaking changes (2):
[breaking] User.email — field removed
[breaking] User.role — type changed: string → "admin" | "editor"
Non-breaking changes (1):
[ok] User.nickname — field addedDetected change types
| Change | Breaking |
|---|---|
Type removed | Yes |
Field removed | Yes |
Field type changed | Yes |
Nullability changed | Yes |
Enum values changed | Yes |
Optional field became required | Yes |
Required field added | Yes |
Type added | No |
Optional field added | No |
Required field became optional | No |
CI/CD integration
# GitHub Actions example
- name: Check for breaking type changes
run: npx snaptype diff types/v1.ts types/v2.ts --ci
env:
SNAPTYPE_LICENSE_KEY: ${{ secrets.SNAPTYPE_LICENSE_KEY }}mock Pro
Generate representative mock data from a JSON file.
snaptype mock <file> [options]Examples
# JSON output (default)
snaptype mock schema.json -o mocks/data.json
# TypeScript const export
snaptype mock schema.json --ts -o mocks/data.tsTypeScript output (--ts)
export const mockUser = {
id: 0,
email: "user@example.com",
createdAt: "2024-01-01T00:00:00.000Z",
active: true,
} as const;Options
| Flag | Description |
|---|---|
-o, --output <file> | Output file path |
--ts | Emit a TypeScript as const export instead of raw JSON |
to-zod Pro
Convert existing TypeScript interfaces and type aliases to Zod schemas.
snaptype to-zod <file> [options]Examples
# Convert a file of interfaces to Zod
snaptype to-zod src/types/user.ts -o src/schemas/user.ts
# With readonly
snaptype to-zod src/types/user.ts --readonly -o src/schemas/user.tsInput / output
export interface User {
id: number;
email: string;
role: "admin" | "user";
address?: Address;
}
export type Status = "active" | "inactive" | "pending";import { z } from 'zod';
export const UserSchema = z.object({
id: z.number(),
email: z.string(),
role: z.enum(["admin", "user"]),
address: AddressSchema.optional(),
});
export type User = z.infer<typeof UserSchema>;
export const StatusSchema = z.enum(["active", "inactive", "pending"]);
export type Status = z.infer<typeof StatusSchema>;Options
| Flag | Description |
|---|---|
-o, --output <file> | Output file path |
-n, --naming <convention> | Naming convention: camel, pascal, snake |
--readonly | Emit .readonly() on all object schemas |
-c, --config <path> | Path to .snaptyperc config file |
Supported types
| TypeScript | Zod output |
|---|---|
string | z.string() |
number | z.number() |
boolean | z.boolean() |
null | z.null() |
unknown, any | z.unknown() |
T[], Array<T> | z.array(...) |
{ ... } (inline object) | z.object({...}) |
"a" | "b" | "c" (string literal union) | z.enum(["a", "b", "c"]) |
A | B (type union) | z.union([...]) |
T | null | z.nullable(...) |
prop? (optional property) | .optional() |
Reference to another type | Schema name (e.g. AddressSchema) |
Limitations
- Only exported interfaces and type aliases are processed — non-exported types are ignored.
- Generic types (Foo<T>) are not supported — the field is emitted as z.unknown().
- readonly properties and index signatures are ignored.
- Intersection types (A & B) are not supported.
- No semantic hints — email: string stays z.string(), not z.email(). Use from-json / from-url on actual data to get semantic validation.
Output options
TypeScript vs Zod
By default, snaptype generates TypeScript interfaces. Use --zod to generate Zod schemas, and combine with --ts to get both.
| Flags | Output |
|---|---|
(none) | TypeScript only |
--zod | Zod only |
--zod --ts | Both TypeScript and Zod |
When generating both, the Zod file is placed next to the TS file with a .zod.ts suffix.
TypeScript output
export interface User {
readonly id: number;
email: string; // email
createdAt: string; // ISO 8601
role: "admin" | "user";
}Zod output
import { z } from 'zod';
export const UserSchema = z.object({
id: z.number(),
email: z.email(),
createdAt: z.iso.datetime(),
role: z.enum(["admin", "user"]),
}).readonly();
export type User = z.infer<typeof UserSchema>;Emit style
// --emit interface (default)
export interface User { ... }
// --emit type
export type User = { ... }Configuration file
Create a .snaptyperc file at the root of your project to set default options. CLI flags always take priority over config values. The config file is discovered by walking up the directory tree from the current working directory.
{
"naming": "camel",
"emit": "interface",
"zod": false,
"outDir": "./src/types"
}| Field | Type | Default | Description |
|---|---|---|---|
naming | "camel" | "pascal" | "snake" | "camel" | Naming convention for generated property and type names |
emit | "interface" | "type" | "interface" | TypeScript declaration style |
zod | boolean | false | Generate a Zod schema (in addition to or instead of TypeScript) |
ts | boolean | false | Also emit the TypeScript file when zod is true |
readonly | boolean | false | Add readonly to every property (TS) or .readonly() on the root schema (Zod) |
zodImport | "named" | "namespace" | "cjs" | "named" | Import style in generated Zod files |
outDir | string | — | Output directory when -o is not provided |
baseUrl | string | — | Prefix prepended to relative URLs in from-url and from-graphql |
headers | Record<string, string> | — | Default HTTP headers for from-url and from-graphql requests |
Semantic inference
snaptype inspects actual values in your data and applies semantic hints to produce more precise types and Zod validators. No configuration required. For each string field, snaptype samples up to 50 values — if ≥ 60% match a known pattern, the hint is applied. This allows fields that mix valid values with empty strings or nulls to still be detected.
| Detected pattern | Example value | TS output | Zod output |
|---|---|---|---|
ISO 8601 date | "2024-01-15T10:30:00.000Z" | string // ISO 8601 | z.iso.datetime() |
Email address | "hello@example.com" | string // email | z.email() |
URL | "https://example.com/img.png" | string // url | z.url() |
Semantic hints take priority over enum detection — a field detected as email or datetime is never emitted as a union literal, even if it has low cardinality. When merging multiple files or URLs, a hint is kept only if all sources agree on the same pattern; conflicting hints are dropped and the field stays as string.
Enum detection
When a string field has a small number of distinct values (≤ 10) appearing in at least 80% of samples, snaptype automatically promotes it to a union literal. A minimum of 2 distinct values is required — a field with only one unique value stays as string.
[
{ "role": "admin" },
{ "role": "user" },
{ "role": "user" },
{ "role": "moderator" }
]export interface Record {
role: "admin" | "user" | "moderator";
}
export const RecordSchema = z.object({
role: z.enum(["admin", "user", "moderator"]),
});Naming conventions
Applied to both type names and property names at generation time. Raw field names from the source are always preserved internally.
| Convention | Example input | Output |
|---|---|---|
camel (default) | user_id, UserID | userId |
pascal | user_id, userId | UserId |
snake | userId, UserID | user_id |
Interface and type alias names are always PascalCase regardless of the --naming flag. The convention only affects property names.
Environment variables
| Variable | Description |
|---|---|
SNAPTYPE_LICENSE_KEY | JWT license key. Required for Pro features. |
SNAPTYPE_API_URL | Override the Snaptype API endpoint. Defaults to https://api.snaptype.dev. |
Setting the license key
# Temporary (current session)
export SNAPTYPE_LICENSE_KEY=your-key-here
# Permanent (add to your shell profile)
echo 'export SNAPTYPE_LICENSE_KEY=your-key-here' >> ~/.zshrc