# quicktype: generating typed models from JSON, Schema and GraphQL

> quicktype turns sample JSON, JSON Schema, TypeScript or GraphQL queries into model code for more than twenty target languages. It is a code generator with a real workflow behind it, and the workflow is the part worth judging.

**glideapps/quicktype** — Generate types and converters from JSON, Schema, and GraphQL

- Repository: https://github.com/glideapps/quicktype
- Website: https://app.quicktype.io
- Stars: 13,879 · Forks: 1,194
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/glideapps-quicktype

## The problem quicktype solves, and who actually needs it

Hand-writing a model class from a JSON response is a small task that repeats forever. The response gains a field, the model does not, and the mismatch surfaces at runtime rather than at compile time. quicktype takes the sample payload you already have and emits the classes, structs or interfaces that describe it, in a language you choose. The README frames the goal as working with JSON type-safely across many programming languages, and the target list is long: Ruby, JavaScript, Flow, Rust, Kotlin, Dart, Python, C#, Go, C++, Java, Scala, TypeScript, Swift, Objective-C, Elm, JSON Schema, Pike, Prop-Types, Haskell and PHP.

The people who get the most out of it are not writing a single client. They are maintaining the same wire format in an iOS app, an Android app and a Node service, where three hand-written models drift apart in three different ways. The README's recommended flow says the generated models will serialize to and from the same JSON, so different programs in a stack can communicate. That is the real selling point: one schema, several languages, one source of truth.

It is a poor fit for a payload you do not control and cannot sample well. If the API returns a union of shapes depending on a discriminator field, the inferred model will describe whatever your sample happened to contain, not the full space of responses.

## How quicktype turns a sample into typed code

The pipeline is visible in the repository layout and the JavaScript API. Input is collected into an InputData value: one or more JSON samples, JSON schemas, TypeScript sources or other supported input types. Each input source is added with a name and its samples. quicktype then runs its inference and rendering over that input and produces code for the target language. The npm package quicktype-core exposes this directly, and the README shows jsonInputForTargetLanguage, JSONSchemaInput and FetchingJSONSchemaStore as the pieces you wire together.

The important detail is that inference is per target language. The README's example calls jsonInputForTargetLanguage(targetLanguage), which means the input is prepared with knowledge of where it is going. That is why a JSON number can become an Int in one language and a Double in another, and it is why the same sample can produce different-looking output depending on the -l flag.

Schema input is the more stable path. When you feed quicktype a JSON Schema instead of raw samples, the types come from the schema's declarations rather than from inference over examples. The repository keeps a data/ directory and a test/ directory with fixtures, and the package scripts include test:fixtures, which runs script/test. The output is compared against fixtures, so a change in generated code is expected to show up as a diff. OUTPUT-DIFFS.md at the repository root exists for that reason.

## Installing quicktype and generating your first model

The CLI and the Node.js packages require Node.js 20 or newer, per the README. The recommended install is a global npm install:

```bash
npm install -g quicktype
```

Running it with no arguments prints help and options. The fastest useful test is piping a small object in and naming a target language. This example comes straight from the README and produces C#:

```bash
echo '{ "name": "David" }' | quicktype -l csharp
```

If you omit -l, quicktype infers the language from the output file extension. The README uses a top-level array of numbers saved as Go source:

```bash
echo '[1, 2, 3]' | quicktype -o ints.go
```

For a real project, point it at a file. The long form spells out every option, which is what you will end up putting in a build script:

```bash
quicktype \
  --src person.json \
  --src-lang json \
  --lang swift \
  --top-level Person \
  --out Person.swift
```

You can also point it at a directory of samples, in which case quicktype treats the files as examples of the same type, or at a live URL. The README shows both: a ./blockchain directory containing latest-block.json, transactions.json and marketcap.json rendered as a C++ program, and https://api.somewhere.com/data rendered as Java. Expect the first run on a real payload to produce more types than you wanted, including nested helper types for every object it finds. That is normal and is the point at which you start editing.

## The schema-first workflow quicktype actually recommends

The README is explicit that the best way to use quicktype is not to generate models directly from samples. It is to generate a schema first, review it, commit it, and generate code from the schema during the build. The first command infers a schema from a sample:

```bash
quicktype pokedex.json -l schema -o schema.json
```

After that you edit schema.json by hand. This is the step that matters, because inference guesses. It guesses which fields are optional, what a null means, and whether a number is an integer or a float. A reviewed schema records your decisions instead of the sample's accidents. Once the schema is committed, every language is generated from the same file:

```bash
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
```

The README notes that all of these models serialize to and from the same JSON. That claim is the reason to accept the extra step. It also means the schema file becomes a build input, so it needs to live in version control next to the code it generates, and a schema change has to be reviewed like any other interface change. The README mentions an experimental TypeScript input path as well: generate or write a .ts file with interfaces, then run quicktype over it. The README marks that path experimental, so treat it as the less settled of the two.

## Where quicktype gets in the way

Inference is only as good as the sample. A field that is absent from your sample is absent from the generated model, and a field that is null in your sample may be typed as nullable even when the API only returns null in an error case. The schema-first workflow exists to fix this, but it shifts the work onto you: you have to read the inferred schema and correct it. Teams that skip that review and generate straight from samples get models that compile and then fail on the first response that differs from the sample.

Polymorphic payloads are the other soft spot. If a single endpoint returns different object shapes depending on a type field, the generated model will reflect the shapes present in your input. The README does not describe a discriminator-aware inference mode, so this is a case where you should expect to edit the schema by hand or write the model yourself.

The JavaScript API is also not a one-liner. The README's example builds an InputData value, adds each source by name, and then calls quicktype with that value and options. If you only want a type from a string, the CLI is shorter. The quicktype-core package is for people embedding generation into a larger tool, and the setup cost reflects that.

Finally, the version in package.json is 24.0.0 while the most recent release listed is v26.0.0, so the repository's package manifest and the published release tags are not in lockstep. If you pin versions, check the tag you are installing rather than assuming the manifest reflects it.

## quicktype against hand-written models and schema-first tools

The obvious alternative is writing the model by hand, and for a single language it is often the right call. A hand-written Swift struct is shorter than a generated one, carries only the fields you use, and does not need a regeneration step when the API changes. The difference in approach is where the type information lives. With hand-written models, the JSON shape is documented in prose or in the developer's head. With quicktype, it lives in a schema file that is checked in and used to produce every language's model.

That trade favors quicktype as the number of target languages grows. Two languages is arguable. Five is not: the schema file becomes the only place where the wire format is defined, and the generated code in each language is a build artifact. The cost is the review step, and the repository acknowledges it with fixture tests and an OUTPUT-DIFFS.md file, so generated-code changes are visible in review rather than silent.

A second alternative is to generate types only, without serializers. The README shows a --just-types flag in the TypeScript example, which infers a .ts file from a sample. If your runtime already handles JSON binding, generating serializers is dead code. The flag exists, and using it keeps the generated surface small.

## Maintenance, licensing and what an upgrade costs

The repository is not archived, and the last push was on 2026-09-13, so it is being worked on. The release history shows v26.0.0 on 2026-07-20, preceded by v26.0.0-pre1 the same day and v25.1.0 on 2026-07-19, which suggests a steady release cadence rather than a single long-lived branch.

Upgrades are not free. The README points to MIGRATING.md for upgrade details and states that the CLI and Node.js packages require Node.js 20 or newer. The repository's package.json sets engines.node to >=20.19.0, which is stricter than the README's phrasing, so a build image on an early Node 20 release may fail even though the README says 20 or newer. Check the exact patch level your CI uses.

The generated code is the other upgrade cost. When quicktype changes its output, your diff changes, and the repository's fixture tests and OUTPUT-DIFFS.md are the mechanism for seeing that. If you generate into version control, an upgrade produces a large but reviewable diff. If you generate during the build and do not commit the output, the upgrade is invisible until something stops compiling.

quicktype is licensed under Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. The LICENSE file at the repository root is the authoritative text. That is a description of the licence, not legal advice; if your organization has rules about generated code and attribution, have someone read the licence rather than this paragraph.

## Conclusion

Adopt quicktype if you have a stable JSON payload, a schema you are willing to review and commit, and more than one language in the stack that has to agree on the same wire format. Skip it if your payload is unstable, deeply polymorphic, or if you only need a one-off type and would rather hand-write it. Before committing, run the schema round trip described above on your own sample, check the generated file for optionality and date handling, and confirm the Node.js version your build image ships, because the CLI and Node packages require Node.js 20 or newer.

## FAQ

### How do I use quicktype?

Install it globally with npm install -g quicktype, then run it with no arguments to see the options. The shortest path is to pipe a sample into it with a target language, for example echo '{ "name": "David" }' | quicktype -l csharp, or to point it at a file such as quicktype person.json -o Person.swift.

### Is there a JSON to C# converter available?

Yes. quicktype lists C# among its target languages, and the README's first CLI example pipes a JSON object into quicktype with -l csharp to produce C# output.

### How can I convert JSON to Swift models?

Run quicktype against a JSON file with Swift as the target language, for example quicktype person.json -o Person.swift, or spell out the options with --src, --src-lang json, --lang swift, --top-level and --out. Swift is listed in the README's target languages.

### What is quicktype?

quicktype generates strongly-typed models and serializers from JSON, JSON Schema, TypeScript and GraphQL queries, for a long list of target languages including TypeScript, Python, Go, Rust, Swift and C#. It is available as a CLI, as Node.js packages, and as a browser app at app.quicktype.io.

### What are the alternatives to app.quicktype.io?

The same generator is available outside the web app: the npm package quicktype installs a CLI, and the quicktype-core package exposes the generator as a JavaScript function you can call from Node or the browser. The README notes the web app also works offline and does not send sample data over the Internet.

## Sources

- [glideapps/quicktype on GitHub](https://github.com/glideapps/quicktype)
- [License: Apache-2.0](https://github.com/glideapps/quicktype/blob/master/LICENSE)
- [Project website](https://app.quicktype.io)
- [README](https://github.com/glideapps/quicktype/blob/master/README.md)
- [Releases](https://github.com/glideapps/quicktype/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/glideapps-quicktype
