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
npx snaptype from-json users.json -o src/types/user.ts
# Zod schema from a REST API response
npx snaptype from-url https://api.example.com/users -o src/schemas/user.ts --zod
# Both TypeScript and Zod at once
npx snaptype from-json data.json --zod --ts -o src/types.tsfrom-json
Full guide: generate TypeScript types from JSON →Generate TypeScript types or Zod schemas from one or more JSON files.
npx snaptype from-json <file> [options]Sample input file
Download users.json[
{
"id": 1,
"email": "alice@example.com",
"role": "admin",
"createdAt": "2024-01-15T10:30:00.000Z",
"score": 98.5
},
{
"id": 2,
"email": "bob@example.com",
"role": "user",
"createdAt": "2024-03-22T08:00:00.000Z",
"score": 72.0
}
]Examples
# Single file
npx snaptype from-json data.json -o src/types/data.ts
# Override the root type name
npx snaptype from-json response.json --name ApiResponse -o src/types.ts
# Zod schema output
npx snaptype from-json data.json --zod -o src/schemas/data.ts
# Both TypeScript and Zod
npx snaptype from-json data.json --zod --ts -o src/types.ts
# Multiple files — merged into one unified type (Pro)
npx 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.
npx snaptype from-url <url> [options]Examples
# From a REST API
npx snaptype from-url https://api.github.com/users/octocat -o src/github.ts
# Custom root name
npx snaptype from-url https://api.example.com/me --name CurrentUser -o src/me.ts
# With authentication header
npx snaptype from-url https://api.example.com/me \
-H "Authorization: Bearer $TOKEN" \
-o src/me.ts
# Multiple endpoints merged — absent fields become optional (Pro)
npx 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
Full guide: generate Zod schema 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.
npx snaptype from-csv <file> [options]Sample input file
Download users.csvid,email,role,score,createdAt
1,alice@example.com,admin,98.5,2024-01-15T10:30:00.000Z
2,bob@example.com,user,72.0,2024-03-22T08:00:00.000Z
3,carol@example.com,user,88.3,2024-06-10T14:00:00.000Z
4,dave@example.com,moderator,,2024-09-01T09:00:00.000ZExamples
# TypeScript interfaces from CSV
npx snaptype from-csv data.csv -o src/types/row.ts
# Snake case property names
npx snaptype from-csv data.csv --naming snake -o src/types/row.ts
# File without a header row — provide column names manually
npx snaptype from-csv data.csv \
--columns id,name,score,active \
-o src/types/row.ts
# Watch mode — regenerates on every file save (Pro)
npx 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.
npx snaptype from-stdin --name <TypeName> [options]Examples
# Pipe from curl
curl https://api.example.com/me | npx snaptype from-stdin --name CurrentUser
# Pipe from another command
cat response.json | npx snaptype from-stdin --name ApiResponse -o src/types.ts
# With Zod output
curl https://api.example.com/products | npx snaptype from-stdin --name Product --zodWithout -o, output is written to stdout — useful for previewing or piping further:
cat data.json | npx snaptype from-stdin --name UserOptions
| Flag | Description |
|---|---|
--name <name> | Required. Root type name |
from-openapi
Full guide: generate TypeScript types 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.
npx snaptype from-openapi <source> [options]Sample input file
Download openapi.yamlopenapi: "3.0.3"
info:
title: My API
version: "1.0.0"
components:
schemas:
User:
type: object
required: [id, email]
properties:
id:
type: integer
email:
type: string
format: email
role:
type: string
enum: [admin, user, moderator]
address:
$ref: '#/components/schemas/Address'
Address:
type: object
required: [street, city]
properties:
street:
type: string
city:
type: string
zip:
type: stringExamples
# One file per schema (default) — output must be a directory
npx snaptype from-openapi ./openapi.yaml -o ./src/types/
# All schemas in a single file
npx snaptype from-openapi ./openapi.yaml --single-file -o ./src/api-types.ts
# Remote spec
npx snaptype from-openapi https://petstore3.swagger.io/api/v3/openapi.json -o ./types/
# With Zod schemas
npx 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.
npx 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.
Sample generated output
Given a GraphQL API with a User type, snaptype generates one file per type:
export interface User {
id: string;
email: string;
role: "admin" | "user" | "moderator";
posts: Post[];
createdAt: string;
}export interface Post {
id: string;
title: string;
body: string;
published: boolean;
author: User;
}Examples
# Public endpoint
npx snaptype from-graphql https://api.example.com/graphql -o src/graphql-types/
# With authentication header
npx 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.
npx snaptype barrel <dir> [options]Examples
# Default: outputs <dir>/index.ts
npx snaptype barrel ./src/types
# Custom output path
npx snaptype barrel ./src/types -o src/types/index.ts
# Watch mode — regenerates when files are added or removed
npx 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.
npx snaptype diff <old> <new> [options]Examples
# Compare two versions
npx snaptype diff types-v1.ts types-v2.ts
# CI mode — exits with code 1 if breaking changes are found
npx 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.
npx snaptype mock <file> [options]Examples
# JSON output (default)
npx snaptype mock schema.json -o mocks/data.json
# TypeScript const export
npx 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.
npx snaptype to-zod <file> [options]Examples
# Convert a file of interfaces to Zod
npx snaptype to-zod src/types/user.ts -o src/schemas/user.ts
# With readonly
npx 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.
activate / deactivate / license
Commands for managing your Pro licence key.
npx snaptype activate
npx snaptype activate <key>Validates the key and stores it locally. Once activated, all Pro features are available without setting any environment variable. The key is cached for 24 hours and revalidated automatically on the next Pro command.
npx snaptype activate xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# ✓ License activated (xxxxxxxx…)npx snaptype deactivate
npx snaptype deactivateRemoves the local licence record. Useful before transferring a key to another machine. If the network is unreachable, the local record is still removed and a warning is printed.
npx snaptype deactivate
# ✓ License deactivatednpx snaptype license
npx snaptype licenseShows the status of the currently activated licence.
npx snaptype license
# ✓ Active xxxxxxxx… (cache valid until 02/05/2026 10:34:00)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";
}Arrays
Array item types are inferred from the values observed in the data.
| Items observed | Emitted type |
|---|---|
All the same type | string[], number[], … |
2 distinct types | (string | number)[] — union |
3 or more distinct types | unknown[] |
Non-primitive mixed with primitives | unknown[] |
export interface Stats {
labels: (string | number)[]; // 2 distinct types → union
mixed: unknown[]; // 3+ types → unknown
}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();Emit style
// --emit interface (default)
export interface User { ... }
// --emit type
export type User = { ... }Configuration file
Create a .snaptyperc or .snaptyperc.json file at the root of your project. All keys are optional — any key you omit falls back to its default. CLI flags always take priority.
{
"naming": "pascal",
"emit": "interface",
"zod": true,
"ts": true,
"readonly": false,
"zodImport": "named",
"zodInfer": true,
"outDir": "src/types",
"baseUrl": "https://api.example.com",
"headers": {
"Authorization": "Bearer my-token"
}
}| Key | Type | Default | Description |
|---|---|---|---|
naming | "camel" | "pascal" | "snake" | "camel" | Naming convention applied to 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 | When zod is true, also emit the TypeScript file |
readonly | boolean | false | Add readonly to every property (TS) or .readonly() on the root schema (Zod) |
zodImport | "named" | "namespace" | "cjs" | "named" | Import style used in generated Zod files |
zodInfer | boolean | true | Emit export type X = z.infer<typeof XSchema> alongside each Zod schema |
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 |
outDir | string | — | Output directory used when -o is not provided |
naming
Controls how property names and interface names are emitted. Applied at generation time only — the internal schema always stores names as-is.
| Value | Example |
|---|---|
camel (default) | firstName, userProfile |
pascal | FirstName, UserProfile |
snake | first_name, user_profile |
emit
Switches between interface and type alias for generated TypeScript declarations. Has no effect on Zod output.
// emit: "interface"
export interface User { id: number; }
// emit: "type"
export type User = { id: number; };zod and ts
| zod | ts | Output |
|---|---|---|
false | false | TypeScript only |
true | false | Zod only |
true | true | Both TypeScript and Zod |
The Zod file is written alongside the TypeScript file with a .zod.ts suffix (out.ts → out.zod.ts).
zodImport
Controls the import statement emitted at the top of generated Zod files.
| Value | Generated import |
|---|---|
named (default) | import { z } from 'zod'; |
namespace | import * as z from 'zod'; |
cjs | const { z } = require('zod'); |
zodInfer
When true (default), each schema is followed by an inferred type alias:
export const UserSchema = z.object({ ... });
export type User = z.infer<typeof UserSchema>; // emitted when zodInfer: trueSet to false to emit schemas only — useful when combining zod: true with ts: true, since TypeScript interfaces are already generated in the .ts file.
{ "zod": true, "ts": true, "zodInfer": false }baseUrl
Used by from-url and from-graphql when the URL argument does not start with http. If the argument is already absolute, baseUrl is ignored.
# .snaptyperc: { "baseUrl": "https://api.example.com" }
# resolves to https://api.example.com/users
npx snaptype from-url /users -o types.tsheaders
Default headers sent with every HTTP request made by from-url and from-graphql. Headers passed with -H on the CLI take priority when the same key is present in both.
{
"headers": {
"Authorization": "Bearer my-token",
"X-Tenant": "acme"
}
}outDir
When -o is not provided, snaptype derives the output filename from the source and writes it into outDir. The directory is created automatically if it does not exist.
# .snaptyperc: { "outDir": "src/types" }
# writes to src/types/users.ts
npx snaptype from-json ./data/users.jsonConfig file discovery
snaptype searches for .snaptyperc or .snaptyperc.json starting from the current working directory and walking up toward the filesystem root. To point to a specific file:
npx snaptype from-json ./data.json -o out.ts --config ./configs/snaptype.jsonValidation
Invalid values are ignored with a warning and the built-in default is used instead.
snaptype: invalid naming "kebab", using "camel"
snaptype: "zod" must be a boolean, ignoringSemantic 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. |
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' >> ~/.zshrcFeedback & support
Found a bug, have a feature request, or need help with a specific use case? Reach out directly — every message is read.
- Bug reports
- Feature requests
- Questions about a command or output format
- Edge cases in your data that snaptype doesn't handle well