Documentation

JSON, CSV, OpenAPI, GraphQL → TypeScript interfaces or Zod schemas. In one command.

Installation

npm install -D snaptype

Requires 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.ts

from-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
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.ts

Options

FlagDescription
--name <name>Override the root type name
--watchRegenerate 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.ts

Options

FlagDescription
--name <name>Override the root type name
-H, --header <header>HTTP header, repeatable. Format: "Name: Value"
--watchRe-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.csv
users.csv
id,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.000Z

Examples

# 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.ts

Options

FlagDescription
--columns <col1,col2,...>Column names when the file has no header row
--watchRe-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 --zod

Without -o, output is written to stdout — useful for previewing or piping further:

cat data.json | npx snaptype from-stdin --name User

Options

FlagDescription
--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.yaml
openapi.yaml
openapi: "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: string

Examples

# 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

FlagDescription
--single-fileOutput 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:

src/graphql-types/User.ts
export interface User {
  id: string;
  email: string;
  role: "admin" | "user" | "moderator";
  posts: Post[];
  createdAt: string;
}
src/graphql-types/Post.ts
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

FlagDescription
-H, --header <header>HTTP header forwarded to the GraphQL endpoint. Repeatable. Format: "Name: Value"

Type mapping

GraphQL typeOutput
String, IDstring
Int, Floatnumber
Booleanboolean
Custom scalarunknown
OBJECT, INPUT_OBJECTinterface with fields
ENUMtype Foo = "A" | "B"
UNION, INTERFACEtype Foo = A | B | C
NON_NULL wrapperfield is not optional, not nullable
LIST wrapperfield: 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 --watch

Generated output

// Generated by snaptype — do not edit manually
export * from './user.js';
export * from './post.js';
export * from './product.js';

Options

FlagDescription
-o, --output <file>Output path (default: <dir>/index.ts)
--watchRegenerate 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 --ci

Output 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 added

Detected change types

ChangeBreaking
Type removedYes
Field removedYes
Field type changedYes
Nullability changedYes
Enum values changedYes
Optional field became requiredYes
Required field addedYes
Type addedNo
Optional field addedNo
Required field became optionalNo

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.ts

TypeScript output (--ts)

export const mockUser = {
  id: 0,
  email: "user@example.com",
  createdAt: "2024-01-01T00:00:00.000Z",
  active: true,
} as const;

Options

FlagDescription
-o, --output <file>Output file path
--tsEmit 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.ts

Input / output

src/types/user.ts
export interface User {
  id: number;
  email: string;
  role: "admin" | "user";
  address?: Address;
}

export type Status = "active" | "inactive" | "pending";
src/schemas/user.ts
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

FlagDescription
-o, --output <file>Output file path
-n, --naming <convention>Naming convention: camel, pascal, snake
--readonlyEmit .readonly() on all object schemas
-c, --config <path>Path to .snaptyperc config file

Supported types

TypeScriptZod output
stringz.string()
numberz.number()
booleanz.boolean()
nullz.null()
unknown, anyz.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 | nullz.nullable(...)
prop? (optional property).optional()
Reference to another typeSchema 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 deactivate

Removes 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 deactivated

npx snaptype license

npx snaptype license

Shows 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.

FlagsOutput
(none)TypeScript only
--zodZod only
--zod --tsBoth 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 observedEmitted type
All the same typestring[], number[], …
2 distinct types(string | number)[] — union
3 or more distinct typesunknown[]
Non-primitive mixed with primitivesunknown[]
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 = { ... }

Shared flags

Available on all from-* commands and to-zod.

FlagDefaultDescription
-o, --output <file>stdoutOutput file path. For from-openapi without --single-file, provide a directory.
--zodfalseGenerate Zod schemas
--tsfalseAlso generate TypeScript when --zod is set
-n, --naming <convention>camelNaming convention: camel, pascal, snake
--emit <kind>interfaceDeclaration style: interface or type
--readonlyfalseEmit readonly on all properties
-c, --config <path>auto-detectedPath to .snaptyperc config file
--watchfalseRe-run when source file(s) change (Pro)

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.

.snaptyperc
{
  "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"
  }
}
KeyTypeDefaultDescription
naming"camel" | "pascal" | "snake""camel"Naming convention applied to generated property and type names
emit"interface" | "type""interface"TypeScript declaration style
zodbooleanfalseGenerate a Zod schema in addition to (or instead of) TypeScript
tsbooleanfalseWhen zod is true, also emit the TypeScript file
readonlybooleanfalseAdd readonly to every property (TS) or .readonly() on the root schema (Zod)
zodImport"named" | "namespace" | "cjs""named"Import style used in generated Zod files
zodInferbooleantrueEmit export type X = z.infer<typeof XSchema> alongside each Zod schema
baseUrlstringPrefix prepended to relative URLs in from-url and from-graphql
headersRecord<string, string>Default HTTP headers for from-url and from-graphql requests
outDirstringOutput 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.

ValueExample
camel (default)firstName, userProfile
pascalFirstName, UserProfile
snakefirst_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

zodtsOutput
falsefalseTypeScript only
truefalseZod only
truetrueBoth TypeScript and Zod

The Zod file is written alongside the TypeScript file with a .zod.ts suffix (out.tsout.zod.ts).

zodImport

Controls the import statement emitted at the top of generated Zod files.

ValueGenerated import
named (default)import { z } from 'zod';
namespaceimport * as z from 'zod';
cjsconst { 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: true

Set 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.ts

headers

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.json

Config 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.json

Validation

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, ignoring

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 patternExample valueTS outputZod output
ISO 8601 date"2024-01-15T10:30:00.000Z"string // ISO 8601z.iso.datetime()
Email address"hello@example.com"string // emailz.email()
URL"https://example.com/img.png"string // urlz.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.

input
[
  { "role": "admin" },
  { "role": "user" },
  { "role": "user" },
  { "role": "moderator" }
]
output
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.

ConventionExample inputOutput
camel (default)user_id, UserIDuserId
pascaluser_id, userIdUserId
snakeuserId, UserIDuser_id

Interface and type alias names are always PascalCase regardless of the --naming flag. The convention only affects property names.

Environment variables

VariableDescription
SNAPTYPE_LICENSE_KEYJWT 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' >> ~/.zshrc

Feedback & 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

hello@snaptype.dev