# Technical Documentation: glideapps/quicktype

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/glideapps/quicktype)

### Overview (`README.md`)

[](https://badge.fury.io/js/quicktype)
[](https://github.com/glideapps/quicktype/actions/workflows/test-pr.yaml)

`quicktype` generates strongly-typed models and serializers from JSON, JSON Schema, TypeScript, and [GraphQL queries](https://blog.quicktype.io/graphql-with-quicktype/), making it a breeze to work with JSON type-safely in many programming languages.

-   [Try `quicktype` in your browser](https://app.quicktype.io).
-   Read ['A first look at quicktype'](http://blog.quicktype.io/first-look/) for more introduction.
-   If you have any questions, check out the [FAQ](FAQ.md) first.

### Supported Inputs

| JSON | JSON API URLs | [JSON Schema](https://app.quicktype.io/#s=coordinate) |
| ---- | ------------- | ----------------------------------------------------- |

| TypeScript | GraphQL queries |
| ---------- | --------------- |

### Target Languages

| [Ruby](https://app.quicktype.io/#l=ruby) | [JavaScript](https://app.quicktype.io/#l=js) | [Flow](https://app.quicktype.io/#l=flow) | [Rust](https://app.quicktype.io/#l=rust) | [Kotlin](https://app.quicktype.io/#l=kotlin) |
| ---------------------------------------- | -------------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------------------------------------------- |

| [Dart](https://app.quicktype.io/#l=dart) | [Python](https://app.quicktype.io/#l=python) | [C#](https://app.quicktype.io/#l=cs) | [Go](https://app.quicktype.io/#l=go) | [C++](https://app.quicktype.io/#l=cpp) |
| ---------------------------------------- | -------------------------------------------- | ------------------------------------ | ------------------------------------ | -------------------------------------- |

| [Java](https://app.quicktype.io/#l=java) | [Scala](https://app.quicktype.io/#l=scala3) | [TypeScript](https://app.quicktype.io/#l=ts) | [Swift](https://app.quicktype.io/#l=swift) | [Objective-C](https://app.quicktype.io/#l=objc) | [Elm](https://app.quicktype.io/#l=elm) |
| ---------------------------------------- | ------------------------------------------- | -------------------------------------------- | ------------------------------------------ | ----------------------------------------------- | -------------------------------------- |

| [JSON Schema](https://app.quicktype.io/#l=schema) | [Pike](https://app.quicktype.io/#l=pike) | [Prop-Types](https://app.quicktype.io/#l=javascript-prop-types) | [Haskell](https://app.quicktype.io/#l=haskell) | [PHP](https://app.quicktype.io/#l=php) |
| ------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------- | -------------------------------------- |

_Missing your favorite language? Please implement it!_

## Installation

There are many ways to use `quicktype`. [app.quicktype.io](https://app.quicktype.io) is the most powerful and complete UI. The web app also works offline and doesn't send your sample data over the Internet, so paste away!

The quicktype CLI and Node.js packages require Node.js 20 or newer. See
[Migrating to quicktype 24](MIGRATING.md) for upgrade details.

For the best CLI, we recommend installing `quicktype` globally via `npm`:

```bash
npm install quicktype
```

## Using `quicktype`

```bash
# Run quicktype without arguments for help and options
quicktype

# quicktype a simple JSON object in C#
echo '{ "name": "David" }' | quicktype -l csharp

# quicktype a top-level array and save as Go source
echo '[1, 2, 3]' | quicktype -o ints.go

# quicktype a sample JSON file in Swift
quicktype person.json -o Person.swift

# A verbose way to do the same thing
quicktype \
  --src person.json \
  --src-lang json \
  --lang swift \
  --top-level Person \
  --out Person.swift

# quicktype a directory of samples as a C++ program
# Suppose ./blockchain is a directory with files:
#   latest-block.json transactions.json marketcap.json
quicktype ./blockchain -o blockchain-api.cpp

# quicktype a live JSON API as a Java program
quicktype https://api.somewhere.com/data -o Data.java
```

### Generating code from JSON schema

The recommended way to use `quicktype` is to generate a JSON schema from sample data, review and edit the schema, commit the schema to your project repo, then generate code from the schema as part of your build process:

```bash
# First, infer a JSON schema from a sample.
quicktype pokedex.json -l schema -o schema.json

# Review the schema, make changes,
# and commit it to your project repo.

# Finally, generate model code from schema in your
# build process for whatever languages you need:
quicktype -s schema schema.json -o src/ios/models.swift
quicktype -s schema schema.json -o src/android/Models.java
quicktype -s schema schema.json -o src/nodejs/Models.ts

# All of these models will serialize to and from the same
# JSON, so different programs in your stack can communicate
# seamlessly.
```

### Generating code from TypeScript (Experimental)

You can achieve a similar result by writing or generating a [TypeScript](http://www.typescriptlang.org/) file, then quicktyping it. TypeScript is a typed superset of JavaScript with simple, succinct syntax for defining types:

```typescript
interface Person {
    name: string;
    nickname?: string; // an optional property
    luckyNumber: number;
}
```

You can use TypeScript just like JSON schema was used in the last example:

```bash
# First, infer a TypeScript file from a sample (or just write one!)
quicktype pokedex.json -o pokedex.ts --just-types
# Review the TypeScript, make changes, etc.
quicktype pokedex.ts -o src/ios/models.swift
```

### Calling `quicktype` from JavaScript

You can use `quicktype` as a JavaScript function within `node` or browsers. First add the `quicktype-core` package:

```bash
$ npm install quicktype-core
```

In general, first you create an `InputData` value with one or more JSON samples, JSON schemas, TypeScript sources, or other supported input types. Then you call `quicktype`, passing that `InputData` value and any options you want.

```
/* Detailed source-code truncated for AI context efficiency. */
```

The argument to `quicktype` is a complex object with many optional properties. [Explore its definition](https://github.com/quicktype/quicktype/blob/master/packages/quicktype-core/src/Run.ts#L126) to understand what options are allowed.

#### TypeScript: the `lang` option is a `LanguageName`, not a `string`

In TypeScript, the `lang` option of `quicktype` and the argument of `jsonInputForTargetLanguage` are typed as `LanguageName`, a union of all supported language names — passing a plain `string` is a compile-time error. If the language name is known statically, just pass the literal (`lang: "swift"`). For wrappers that take the language name at runtime — from CLI arguments or configuration — validate it with the `isLanguageName` type guard instead of casting:

```typescript
import { type LanguageName, isLanguageName, quicktype } from "quicktype-core";

async function quicktypeJSON(targetLanguage: LanguageName, typeName: string, jsonString: string) {
    // same body as above
}

const lang = process.argv[2]; // untrusted string
if (!isLanguageName(lang)) {
    throw new Error(`Unknown language: ${lang}`);
}
// lang now has type LanguageName
const { lines } = await quicktypeJSON(lang, "Person", jsonString);
```

#### Bundling `quicktype-core` as ESM

`quicktype-core` ships both CommonJS and ESM builds. If you bundle it into an ESM output for Node with esbuild (`--format=esm --platform=node`), the bundle may throw at runtime:

```
Error: Dynamic require of "process" is not supported
```

This is not specific to quicktype: some of its dependencies (e.g. `yaml`) expose an ESM entry that wraps a CommonJS core, and esbuild replaces `require` calls inside inlined CommonJS with a shim that throws in ESM output. The standard workaround is to inject a `createRequire` banner:

```bash
esbuild main.js --bundle --format=esm --platform=node \
    --banner:js="import { createRequire } from 'module'; const require = createRequire(import.meta.url);"
```

Bundling to CommonJS output (`--format=cjs`) works without any workaround.

### Adding Custom logic or Rendering:

Quicktype supports creating your own custom languages and rendering output, you can extend existing classes or create your own to be using by the `quicktype function`.<br/>
Check out [this guide](./doc/CustomRenderer.md) for more info.

## Contributing

`quicktype` is [Open Source](LICENSE) and we love contributors! In fact, we have a [list of issues](https://github.com/quicktype/quicktype/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Ahelp-wanted) that are low-priority for us, but for which we'd happily accept contributions. Support for new target languages is also strongly desired. If you'd like to contribute, need help with anything at all, or would just like to talk things over, come [join us on Slack](http://slack.quicktype.io/).

### Setup, Build, Run

`quicktype` is implemented in TypeScript and requires `nodejs` and `npm` to build and run.

First, install `typescript` globally via `npm`:

Clone this repo and do:

#### macOS / Linux

```bash
nvm use
npm install
script/quicktype # rebuild (slow) and run (fast)
```

#### Windows

```bash
npm install --ignore-scripts # Install dependencies
npm install typescript # Install typescript globally
tsc --project src/cli # Rebuild
node dist\cli\index.js # Run
```

### Edit

Install [Visual Studio Code](https://code.visualstudio.com/), open this
workspace, and install the recommended extensions:

```bash
code . # opens in VS Code
```

### Live-reloading for quick feedback

When working on an output language, you'll want to view generated
output as you edit. Use `npm start` to watch for changes and
recompile and rerun `quicktype` for live feedback. For example, if you're
developing a new renderer for `fortran`, you could use the following command to
rebuild and reinvoke `quicktype` as you implement your renderer:

```bash
npm start -- "--lang fortran pokedex.json"
```

The command in quotes is passed to `quicktype`, so you can render local `.json`
files, URLs, or add other options.

### Test

```bash
# Run full test suite (unit tests plus all fixtures)
npm test

# Run only the Vitest unit tests
npm run test:unit

# Test a specific language (see test/languages.ts)
FIXTURE=golang npm run test:fixtures

# Test a single sample or directory
FIXTURE=swift npm run test:fixtures -- pokedex.json
FIXTURE=swift npm run test:fixtures -- test/inputs/json/samples
```

---

### Overview (`packages/quicktype-vscode/README.md`)

**Supports** `C (cJSON)`, `C#`, `C++`, `Crystal`, `Dart`, `Elm`, `Flow`, `Go`, `Haskell`, `JSON Schema`, `Java`, `JavaScript`, `JavaScript PropTypes`, `Kotlin`, `Objective-C`, `PHP`, `Pike`, `Python`, `Ruby`, `Rust`, `Scala3`, `Smithy`, `Swift`, `TypeScript`, `TypeScript Effect Schema` and `TypeScript Zod`

-   Interactively generate types and (de-)serialization code from JSON, JSON Schema, and TypeScript
-   Paste JSON/JSON Schema/TypeScript as code



`quicktype` infers types from sample JSON data, then outputs strongly typed models and serializers for working with that data in your desired programming language. For more explanation, read [A first look at quicktype](http://blog.quicktype.io/first-look/).

In any JSON file, use the command "Open quicktype for JSON" to summon quicktype, which will generate types from the JSON. Invoke "Change quicktype's target language" to pick a different language. There are similar "Open quicktype" commands for JSON Schema and TypeScript.

Another way to use quicktype is to copy JSON into the clipboard and invoke "Paste JSON as code/types":



For a more powerful experience, including custom options and the ability to generate code from multiple JSON samples, try [quicktype.io](https://app.quicktype.io).

## Installing

This extension is available for free in the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items/quicktype.quicktype)

## Customization

-   `quicktype.justTypes`: Generate only types, or also produce (de)serialization code when using "Open quicktype". When using "Paste", you can pick between the commands for "types" and "code", without having to set this option.

-   `quicktype.inferMaps`, `quicktype.inferEnums`, `quicktype.inferDateTimes`, `quicktype.inferUuids`, `quicktype.inferBoolStrings`, `quicktype.inferIntegerStrings`: Tell quicktype whether it should try to infer those types from the input JSON. This is not a precise science, so sometimes the guess will be wrong, which is why you can turn them off through these options. Also, quicktype doesn't support dates, UUIDs and stringified integers/booleans in all target languages yet.

## Contribute!

quicktype is an open source project, and we're always happy about contributors. If you can think of a way to improve [this extension](https://github.com/quicktype/quicktype-vscode), or [quicktype](https://github.com/quicktype/quicktype), please consider contributing, especially if you know TypeScript. Code is only one way to contribute, though: we're particularly short on documentation. We'd also love to hear your feedback - come [talk to us on Slack](http://slack.quicktype.io)!

If you find a bug, please [report it on GitHub](https://github.com/quicktype/quicktype-vscode/issues).

---

### Overview (`tools/pr-inbox/README.md`)

# PR inbox

A local browser inbox for reviewing, commenting on, and merging open pull requests.

Use Node 24 and authenticate GitHub CLI first:

```sh
nvm use
npm ci
gh auth login
npm run prs -- --since "4 days"
```

The browser opens at the printed localhost URL. Press Ctrl+C to stop the server. The GitHub token comes from `gh auth token` and stays in server memory.

```sh
npm run prs -- --since "12h" --repo owner/repo --port 4317 --no-open
npm run prs -- --merge-method rebase
```

`--since` accepts hours, days, or weeks. The default repository is `glideapps/quicktype`; the default merge method is `squash`. Other methods are `merge` and `rebase`.

## Shortcuts

- ↑ / ↓: previous / next PR
- ← / →: previous / next file
- D / S: diff / CI
- C: comment; ⌘Enter or Ctrl+Enter: post
- M: merge or enable auto-merge
- ⌘K, Ctrl+K, or /: find a PR
- ?: all shortcuts; Escape: close dialogs

PRs and details load progressively and cache locally. CI and mergeability refresh every 30 seconds. Returning to a disconnected tab reconnects automatically.

## Development

Run `npm run check:prs`, `npm run test:prs`, and `npx biome check tools/pr-inbox package.json`.

---

### Doc Benchmarking (`doc/Benchmarking.md`)

# Pipeline performance benchmark

Run the benchmark from the repository root:

```bash
npm run benchmark:pipeline
```

The command builds `quicktype-core`, warms up every case, and reports median,
p95, and minimum end-to-end times plus maximum observed used heap.  It covers
small and large JSON samples, small and large JSON Schemas, and the TypeScript
and Rust renderers.  Inputs are generated deterministically in memory so
results do not include filesystem I/O.

## Canonical real-world benchmark

Run the canonical benchmark set with:

```bash
npm run benchmark:canonical
```

This command builds `quicktype-core`, gives Node an 8 GiB heap, and runs one
warmup plus three measured passes for both TypeScript and Rust over exactly
these inputs:

- USGS all-month earthquakes GeoJSON
- GitHub REST OpenAPI description
- NVD CVE 2024 feed
- HL7 FHIR R5 combined JSON Schema
- Kestra 0.19 JSON Schema

The inputs are downloaded on the first run and cached outside the repository in
the operating system's user cache directory.  Downloads, decompression, and
filesystem reads are not timed.  Repeated runs use the same snapshots; download
current copies with:

```bash
npm run benchmark:canonical -- --refresh
```

Set `QUICKTYPE_BENCHMARK_CACHE` or pass `--cache-dir DIR` to choose a different
cache location.  The canonical command accepts the same `--warmup`,
`--iterations`, and `--json` options as the synthetic pipeline benchmark.

The end-to-end timer begins before quicktype parses or registers the input and
ends after the generated source has been serialized.  The phase breakdown is:

- **Parse**: compressed JSON parsing for JSON samples, or YAML/JSON parsing for
  JSON Schema.
- **Infer/schema**: type inference from compressed JSON, or conversion from the
  parsed schema to quicktype's initial type graph.
- **Transform**: graph rewrites, map and enum inference, transformations,
  garbage collection, and name gathering.
- **Codegen**: target-language rendering and serialization.
- **Other**: input setup, graph setup, callback overhead, and uninstrumented
  control flow.

The phase breakdown uses the run at the median end-to-end time.  When the
iteration count is even, the two middle runs are interpolated.  This keeps the
phases additive and their percentages at 100%.

Individual pass timings are also printed.  Pass timings are inclusive, and
repeated passes such as `flatten unions` are combined within each run.

`Max heap` is the largest `process.memoryUsage().heapUsed` value observed across
the measured runs for a case.  Heap is sampled before and after input parsing,
after every instrumented quicktype pass, after rendering, and after output
serialization.  Node does not expose an exact JavaScript-heap high-water mark,
so allocations created and released entirely within one synchronous pass might
not appear in this value.  The JSON output records it as
`memory.maximumHeapUsedBytes`.

Use fewer samples for a quick smoke test or emit JSON for comparison tooling:

```bash
npm run benchmark:pipeline -- --warmup 0 --iterations 1
npm run benchmark:pipeline -- --iterations 10 --json > benchmark.json
```

For less garbage-collection noise, invoke the built benchmark directly with
Node's explicit GC enabled:

```bash
npm run build --workspace quicktype-core
node --expose-gc script/benchmark-pipeline.mjs
```

Compare results only on the same machine, Node version, power mode, and command
line.  The benchmark intentionally reports distributions rather than enforcing
a fixed pass/fail threshold.

---

### Doc CustomRenderer (`doc/CustomRenderer.md`)

# Extending quicktype functionality with a Custom Renderer

## quicktype Interface

To customise your rendering output, you can extend existing quicktype classes and override existing methods to achieve the behaviour you want.

This process requires 3 main steps:

1. [Extending a `Renderer` Class](#creating-a-custom-renderer)
2. [Wrapping your `Renderer` in a `TargetLanguage` Class](#creating-a-targetlanguage)
3. [Using your new classes in the `quicktype` function](#using-your-custom-language)
4. [Advanced Usage: Creating an entirely new Language](#creating-a-new-language)

## Creating a custom `Renderer`

Adding custom render logic for an existing language often involves extending a Renderer class and simply overriding or amending one of the `emit` methods:

```ts
// MyCustomRenderer.ts
import { CSharpRenderer } from "quicktype-core";

export class MyCustomRenderer extends CSharpRenderer {
    // Add your custom logic here, feel free to reference the source code for how existing methods work
    //
    // ex.
    protected superclassForType(t: Type): Sourcelike | undefined {
        // if the type is a class, it should extend `GameObject` when rendered in C#
        if (t instanceof ClassType) {
            return "GameObject";
        }
        return undefined;
    }
}
```

## Creating a `TargetLanguage`

If you just want to change the rendering logic for an existing language, you can just extend an exported Language class (`CSharpTargetLanguage` in this example) and override the `makeRenderer` method:

```ts
// MyCustomLanguage.ts
import { CSharpTargetLanguage } from "quicktype-core";

import { MyCustomRenderer } from "./MyCustomRenderer";

export class MyCustomLanguage extends CSharpTargetLanguage {
    // `makeRenderer` instantiates the Renderer class for the TargetLanguage
    protected makeRenderer(
        renderContext: RenderContext,
        untypedOptionValues: Record<string, unknown>
    ): MyCustomRenderer {
        // use your new custom renderer class here
        return new MyCustomRenderer(this, renderContext, getOptionValues(cSharpOptions, untypedOptionValues));
    }
}
```

## Using your custom Language

```ts
import { quicktype } from "quicktype-core";

import { MyCustomLanguage } from './MyCustomLanguage';

const lang = new MyCustomLanguage();

const lines = await quicktype({
	lang: lang, // use your new TargetLanguage in the `lang` field here
	...
});

console.log(lines);
```

## Creating a new Language

If none of the existing `quicktype` Language classes suit your needs, you can creating your own `TargetLanguge` and `Renderer` classes from scratch. If this satisfies your use cases for a language we don't currently support, please consider opening a PR with your new language and we'd love to take a look.

If you run into any issues, you can open a GitHub issue and we'll help you take a look.

### Creating a `TargetLanguage` from scratch

Instead of just extending an existing language, a new Language requires two additional steps:

-   Defining the language config
-   Adding any language-specific options

```ts
import { TargetLanguage, BooleanOption } from "quicktype-core";

// language config
const brandNewLanguageConfig = {
    displayName: "Scratch", // these can be the same
    names: ["scratch"], // these can be the same
    extension: "sb" // the file extension that this language commonly has
} as const;

// language options
const brandNewLanguageOptions = {
    allowFoo: new BooleanOption(
        "allow-foo", // option name
        "Allows Foo", // description
        true // default value
    )
    // The default available Option classes are: StringOption, BooleanOption, EnumOption
    // Please visit the source code for more examples and usage
};

class BrandNewLanguage extends TargetLanguage<typeof brandNewLanguageConfig> {
    public constructor() {
        super(brandNewLanguageConfig);
    }

    public getOptions(): typeof brandNewLanguageOptions {
        return brandNewLanguageOptions;
    }

    protected makeRenderer(
        renderContext: RenderContext,
        untypedOptionValues: Record<string, unknown>
    ): BrandNewRenderer {
        return new BrandNewRenderer(this, renderContext, getOptionValues(brandNewLanguageOptions, untypedOptionValues));
    }
}
```

### Creating a `Renderer` from scratch

Creating a brand new `Renderer` class is very similar to extending an existing class:

```ts
export class BrandNewRenderer extends ConvenienceRenderer {
    public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) {
        super(targetLanguage, renderContext);
    }

    // Additional render methods go here
    // Please reference existing Renderer classes and open a GitHub issue if you need help
}
```

---

### Doc Templates (`doc/Templates.md`)

# NOTE

This was a prototype that we've since removed from quicktype. If you'd like to play with it, please use commit `8eba491ac167a51203eaa6100609ec73ad553236`. If you find it useful and would like us to bring it back, please let us know - it's probably fairly easy.

# Templates

quicktype allows the processing of [Handlebars](http://handlebarsjs.com) templates based on the types specified in or inferred from the input. Templates are always processed in the context of a specific target language, which makes it possible for their output to interact with the types generated for that target language.

## Invocation

    quicktype --lang csharp --template TEMPLATE-FILE ./test/inputs/json/samples/kitchen-sink.json

## Example

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Doc Transformers (`doc/Transformers.md`)

# Transformed string types

quicktype has facilities for transforming JSON strings into other data types, provided a given target language implementation supports it. Right now the most advanced target language in that regard is C#, which supports data/time types and stringified integers.

There are two different sorts of transformed string types:

- Those that transform strings into other JSON-representable types, such as stringified integers.

- Those that transform into types that are not directly representable in JSON (other than as strings), such as date/time types.

Several pieces need to be implemented to add a new transformed string type:

1.  `TransformedStringTypeTargets` have to be added for the new type kind in the object `transformedStringTypeTargetTypeKinds` in `Type.ts`. The property names of that object are the internal primitive type names. Adding a new property automatically adds a new type.

2.  `inferTransformedStringTypeKindForString` in `StringTypes.ts` can optionally be amended to automatically infer the new transformed type from a given string in JSON input. If this isn't done, the only way to use the new type is through JSON Schema. If it is done, a CLI option to turn it off has to be added. This is currently still more complicated than it needs to be, since it also involves changing the options to `quicktype-core`.

3.  The target languages that should support the new type have to be amended. Currently C# is the only one that allows this easily. See `CSharp.ts` and search for `date-time`.

4.  Test cases have to be added. See `test/inputs/schema/date-time*`, for example. If JSON inference is implemented, there should be at least one JSON test file with a string of that type.

5.  In `fixtures.ts`, `ajv`, which we use to validate JSON against schemas, has to be told about the new JSON Schema string format. Search for `date-time`.

## Stuff we need to improve

- Automatic generation of tests. We should have a test generator that produces test files with all string types in all reasonable combinations.

- One CLI option for all string types. No CLI option work should be necessary to implement a new string type.

- The AJV thing should be automated, too. We have almost all the validation code necessary in `StringTypes.ts` anyway.

---

--- METRICS ---
- Files Extracted: 7
- Estimated Token Budget: ~6573 tokens
- Canonical Reference: https://codewiki.google/github.com/glideapps/quicktype
