Technical Documentation: glideapps/quicktype
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
quicktype generates strongly-typed models and serializers from JSON, JSON Schema, TypeScript, and GraphQL queries, making it a breeze to work with JSON type-safely in many programming languages.
- Try
quicktypein your browser. - Read 'A first look at quicktype' for more introduction.
- If you have any questions, check out the FAQ first.
Supported Inputs
| JSON | JSON API URLs | JSON Schema |
|---|
| TypeScript | GraphQL queries |
|---|
Target Languages
| Ruby | JavaScript | Flow | Rust | Kotlin |
|---|
| Dart | Python | C# | Go | C++ |
|---|
| Java | Scala | TypeScript | Swift | Objective-C | Elm |
|---|
| JSON Schema | Pike | Prop-Types | Haskell | PHP |
|---|
Missing your favorite language? Please implement it!
Installation
There are many ways to use quicktype. 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 for upgrade details.
For the best CLI, we recommend installing quicktype globally via npm:
npm install quicktypeUsing `quicktype`
# 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.javaGenerating 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:
# 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 file, then quicktyping it. TypeScript is a typed superset of JavaScript with simple, succinct syntax for defining types:
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:
# 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.swiftCalling `quicktype` from JavaScript
You can use quicktype as a JavaScript function within node or browsers. First add the quicktype-core package:
$ npm install quicktype-coreIn 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 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:
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 supportedThis 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:
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.
Check out this guide for more info.
Contributing
quicktype is Open Source and we love contributors! In fact, we have a list of issues 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.
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
nvm use
npm install
script/quicktype # rebuild (slow) and run (fast)Windows
npm install --ignore-scripts # Install dependencies
npm install typescript # Install typescript globally
tsc --project src/cli # Rebuild
node dist\cli\index.js # RunEdit
Install Visual Studio Code, open this
workspace, and install the recommended extensions:
code . # opens in VS CodeLive-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:
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
# 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/samplesOverview (`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.
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.
Installing
This extension is available for free in the Visual Studio Code Marketplace
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, or 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!
If you find a bug, please report it on GitHub.
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:
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.
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:
npm run benchmark:pipelineThe 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:
npm run benchmark:canonicalThis 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:
npm run benchmark:canonical -- --refreshSet 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 asmemory.maximumHeapUsedBytes.
Use fewer samples for a quick smoke test or emit JSON for comparison tooling:
npm run benchmark:pipeline -- --warmup 0 --iterations 1
npm run benchmark:pipeline -- --iterations 10 --json > benchmark.jsonFor less garbage-collection noise, invoke the built benchmark directly with
Node's explicit GC enabled:
npm run build --workspace quicktype-core
node --expose-gc script/benchmark-pipeline.mjsCompare 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:
- Extending a
RendererClass - Wrapping your
Rendererin aTargetLanguageClass - Using your new classes in the
quicktypefunction - Advanced Usage: Creating an entirely 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:
// 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:
// 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
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
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:
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 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.jsonExample
/* 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:
TransformedStringTypeTargetshave to be added for the new type kind in the objecttransformedStringTypeTargetTypeKindsinType.ts. The property names of that object are the internal primitive type names. Adding a new property automatically adds a new type.inferTransformedStringTypeKindForStringinStringTypes.tscan 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 toquicktype-core.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.tsand search fordate-time.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.In
fixtures.ts,ajv, which we use to validate JSON against schemas, has to be told about the new JSON Schema string format. Search fordate-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.tsanyway.
--- METRICS ---
- Files Extracted: 7
- Estimated Token Budget: ~6573 tokens
- Canonical Reference: https://codewiki.google/github.com/glideapps/quicktype