How to generate types and classes from JSON

The fastest way to get model types for an API is to generate them from a real response: paste the JSON, pick your language and copy the code. A generator reads every value, decides whether it is text, a whole number, a decimal or a date, and turns nested objects into their own types. This guide explains what such a generator can and cannot know from a sample, and what to check before the code goes into your project.

4 min read

Why generate types at all

Typed models catch mistakes early. When the response of an API is described by an interface or a class, your editor completes field names, the compiler notices a misspelled key and a renamed field shows up as an error instead of a silent undefined or null at runtime. Writing these types by hand for a response with fifty fields and three levels of nesting takes time and is easy to get wrong.

A generator does the repetitive part in a second. The result is a good first draft that you then review, rename where needed and commit.

Try it here: JSON to Code

Open the full tool page

What a generator infers from your sample

Everything comes from the values in your JSON. That is why the quality of the sample matters more than anything else.

In the JSONInferred asExample
Textstring"name": "Alex"
Whole numberint, or long above 2,147,483,647"id": 42
Number with a decimal pointdouble or float"price": 19.0
true or falseboolean"active": true
Text in ISO date formatdate type, if enabled"created": "2026-10-27T09:30:00Z"
null in some itemsnullable type"phone": null
Key missing in some itemsoptional field"discount" only in one item
Objecta new named type"address": { ... }
List of objectslist of one merged type"items": [ { ... }, { ... } ]

Give it a sample with variety

A generator can only describe what it sees. If your sample has one order with one item, every field looks required and no field looks nullable. If it has a list of orders where some have a discount and some do not, the discount field is correctly marked optional.

So before you generate, collect a response with several items, ideally including edge cases: a customer without a phone number, an order without items, a product with a decimal price. Put them in one array at the top level and the generator will merge all of them into one type per shape.

  • Fields that are null in every item get a general type such as unknown, object or Any, because the real type is not visible.
  • Empty lists become lists of unknown items for the same reason.
  • A field that is a number in one item and text in another becomes a union in TypeScript and a general type in other languages.
  • Large IDs above 2^53, such as some database keys, are safer as text. JavaScript cannot represent them exactly as numbers.

Names, attributes and conventions

JSON keys often follow the style of the backend, for example snake_case from Python or Ruby, while your client code uses another. A good generator renames fields to the convention of the target language and keeps the original key in an attribute, so serialization still matches the data.

LanguageField namesHow the JSON key is kept
TypeScriptUnchangedNot needed; unusual keys are quoted
C#PascalCase[JsonPropertyName] or [JsonProperty]
Pythonsnake_caseField(alias=...) in Pydantic
GoExported, with ID and URLjson:"key" struct tags
JavacamelCase@JsonProperty (Jackson)
KotlincamelCase@SerialName (kotlinx.serialization)

Types are not validation

A TypeScript interface disappears when the code is compiled. If the API sends something else than the interface promises, nothing stops it at runtime. The same is true for plain classes in most languages: the deserializer fills what it can and leaves the rest empty.

If the data comes from outside your control, validate it when it arrives. In Python, Pydantic models do this out of the box, which is a good reason to choose that style in the generator. In TypeScript, libraries that check data at runtime can be written from the generated interfaces. In C#, Java and Kotlin, mark fields that must be present as required and let the serializer fail early.

A checklist before you commit

  • Rename the top level type from Root to something meaningful, such as Order.
  • Review every field typed unknown, object, Any or JsonElement and replace it with the real type.
  • Check numbers: is a price really a double, or should it be a decimal type for money?
  • Check dates: do you want them as text, or as a date type with a known time zone?
  • Decide which optional fields are truly optional and which only happened to be missing in the sample.
  • Merge types that the generator kept apart only because their samples differed slightly.

Step by step

  1. Paste a JSON responsePaste the response from your API or open a .json file. A list with several items gives better results.
  2. Pick the languageChoose TypeScript, C#, Python, Go, Java or Kotlin, then the style, such as record, dataclass or Pydantic.
  3. Name the top level typeReplace Root in Top level name with the name your project uses, for example Order.
  4. Copy and reviewCopy the code or download it, then go through the checklist in this guide.

Frequently asked questions

Can I generate types from a JSON Schema instead?

This tool works from JSON data, not from a schema. If your API publishes a JSON Schema or an OpenAPI file, a schema based generator gives more precise results, because the schema says what is required.

Why is a field optional in my TypeScript interface?

At least one item in your sample did not have this key. If it is always present in real data, remove the question mark or add a complete item to the sample.

Should money be a double?

For calculations with money, a decimal type such as decimal in C# or BigDecimal in Java avoids rounding errors. A generator only sees a number with a decimal point, so change the type yourself.

What happens to keys with spaces or dashes?

They are converted to valid names in each language, and the original key is kept in an attribute, tag or alias. In TypeScript the key is simply quoted.

Is my JSON uploaded when I generate code here?

No. The generator runs in your browser, so responses with private data stay on your device.