JSON to Mongoose Schema

Generate Mongoose schemas from JSON instantly. Supports JavaScript and TypeScript output, timestamps option, nested objects, and arrays. Free, runs in your browser.

  • Runs in your browser
  • Your data never leaves your browser
  • Free · No Sign-Up
Name the model and root schema. A blank name uses User. Simple names such as User or Order are recommended.
Language JavaScript uses CommonJS require and module.exports. TypeScript uses import/export and document interfaces passed to Schema and model.
timestamps On adds timestamps: true to the root schema. TypeScript also includes createdAt and updatedAt as Date unless those keys already exist in the JSON.
required On adds required: true to primitive, date, mixed and primitive-array fields. Nested schemas and arrays of objects keep their existing form.
Replace the JSON with a user document containing nested objects and arrays, then generate with the current model name and options.
Clear JSON, output and status. Keep the model name and options. Ctrl/⌘+L in this tool also clears the model name.
Enter valid JSON. Input and model-name edits generate after 300 ms; the three option groups update immediately. Invalid JSON clears the output and disables Copy.
Mongoose Schema Output
Copy the complete displayed schema and model export. Copy is disabled when the output is empty.

Enter JSON or load the example to generate a Mongoose schema.

Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.

Type Mapping

  • null fits any type and is skipped; a field that is null in every sample → mongoose.Schema.Types.Mixed
  • a field whose samples have different types (number and string, object and string) → mongoose.Schema.Types.Mixed; ISO date-times mixed with other strings → String
  • string that starts like an ISO 8601 date-time (2026-10-01T09:30:00Z) → Date; a plain date such as 2026-10-01 stays String
  • string → String
  • number → Number
  • boolean → Boolean
  • array of primitives → [String] / [Number] / [Boolean]
  • array of objects → [subSchema] (separate schema generated)
  • nested object → separate schema variable referenced inline

Example

Given this JSON with model name User:

{"username": "alice", "age": 28, "tags": ["admin"], "address": {"city": "London"}}

JavaScript output (timestamps On):

const mongoose = require('mongoose');
const { Schema } = mongoose;

const addressSchema = new Schema({
  city: { type: String },
});

const userSchema = new Schema({
  username: { type: String },
  age: { type: Number },
  tags: [String],
  address: addressSchema,
}, { timestamps: true });

module.exports = mongoose.model('User', userSchema);

Sub-schemas are named after the key (address → addressSchema) and written before the schema that uses them, so the file runs top to bottom. The model name is converted to PascalCase for mongoose.model(); Mongoose then derives the collection name by lowercasing and pluralizing it (User → users).

Example: TypeScript With required On

Model name product, TypeScript, timestamps On, required On:

{"sku":"A-1","price":9.5,"created_at":"2026-10-01T09:30:00Z","release-date":"2026-10-01",
"variants":[{"color":"red","stock":3},{"color":"blue","size":"M"}],"meta":null}
import mongoose, { Schema } from 'mongoose';

export interface IVariants {
color: string;
stock: number;
size: string;
}

export interface IProduct {
sku: string;
price: number;
created_at: Date;
"release-date": string;
variants: IVariants[];
meta: any;
createdAt: Date;
updatedAt: Date;
}

const variantsSchema = new Schema({
color: { type: String, required: true },
stock: { type: Number, required: true },
size: { type: String, required: true },
});

const productSchema = new Schema<IProduct>({
sku: { type: String, required: true },
price: { type: Number, required: true },
created_at: { type: Date, required: true },
"release-date": { type: String, required: true },
variants: [variantsSchema],
meta: { type: mongoose.Schema.Types.Mixed, required: true },
}, { timestamps: true });

export default mongoose.model<IProduct>('Product', productSchema);

Two things to fix by hand before using it:

  • size and stock each appear in only one variant, yet both are required. The array elements are merged into one sub-schema with every key, and the switch applies to all of them.
  • meta was null, so it is Mixed and required: Mongoose would reject the very document you pasted. Give it a real type or drop required.

The interface is a plain document interface, passed as Schema<IProduct> and mongoose.model<IProduct>, as in the Mongoose TypeScript guide (“Using Generics”); it does not extend Document. With timestamps On, Mongoose adds createdAt and updatedAt of type Date (Timestamps), so the interface lists both and doc.createdAt type-checks on a document from new Product() and on a .lean() result. created_at from the JSON is a separate field. If the JSON already has a createdAt or updatedAt key, its own type is kept, because Mongoose then keeps that path as you defined it. The tool’s test compiles every generated TypeScript file with TypeScript 5.9.3 in strict mode against Mongoose 9.10.3.

Keys that are not JavaScript identifiers, such as release-date, are quoted so the generated file parses.

Example: Every Sample Decides the Type

A root array with two orders, model name Order, JavaScript, timestamps Off:

[{"code":1,"note":null,"seller":{"meta":{"x":1}},"buyer":{"meta":{"y":"2"}}},{"code":"A-2","note":"gift","tags":["a",1]}]

Output:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const metaSchema = new Schema({
x: { type: Number },
});

const sellerSchema = new Schema({
meta: metaSchema,
});

const buyerMetaSchema = new Schema({
y: { type: String },
});

const buyerSchema = new Schema({
meta: buyerMetaSchema,
});

const orderSchema = new Schema({
code: { type: mongoose.Schema.Types.Mixed },
note: { type: String },
seller: sellerSchema,
buyer: buyerSchema,
tags: [mongoose.Schema.Types.Mixed],
}, { timestamps: false });

module.exports = mongoose.model('Order', orderSchema);
  • code is 1 in one order and “A-2” in the other, so it is Mixed; Number would reject “A-2”. note is null once and “gift” once, so it is String. tags mixes a string and a number, so its elements are Mixed.
  • The two meta objects have different fields, so the second gets the parent key as a prefix (buyerMetaSchema). Objects under the same key with the same fields and types share one schema; if the prefixed name is taken too, a number is added.

The tool’s test runs each generated JavaScript file with Mongoose 9.10.3, builds a document from every sample, and checks that validateSync() passes and that every field and value comes back (ISO date-times come back as Date, in toISOString() form; an array path missing from a sample comes back as [], Mongoose’s default for arrays).

Limits

  • Mixed accepts anything. A field typed Mixed because its samples disagree is not cast or validated, and Mongoose does not track changes inside it unless you call markModified(). Pick one type when the data allows it.
  • Only objects at the root. In a root array, numbers, strings and arrays next to the objects are ignored; the schema describes the objects.
  • No ObjectId, enum, index or validation. A 24-character hex string stays String; add Schema.Types.ObjectId and ref, unique, enum or min/max yourself.
  • Only the root schema is typed. Sub-schemas get an interface for the root interface to use, but new Schema() for them has no type argument, and fields are not optional even when required is Off. Mongoose does not check that the interface matches the schema (TypeScript guide), so mark optional fields with ? yourself.
  • A root array of primitives such as [“a”, “b”] generates no schema, only the comment // Array of primitives — no schema to generate.

For plain TypeScript types or a Zod schema from the same JSON, use JSON to TypeScript or JSON to Zod.

FAQ

What does this tool generate?

It generates Mongoose schema definitions from JSON. Each nested object becomes its own named schema, and a model export is included at the bottom.

What language modes are supported?

JavaScript (CommonJS require/module.exports) and TypeScript (ES module import/export with a plain document interface passed to Schema<T> and model<T>, as in the Mongoose TypeScript guide).

How are JSON types mapped to Mongoose types?

string → String, number → Number, boolean → Boolean, null → mongoose.Schema.Types.Mixed when every sample is null, array of primitives → [Type], array of objects → separate sub-schema, nested object → separate sub-schema.

What does the timestamps option do?

When On, the schema is created with { timestamps: true }, which automatically adds createdAt and updatedAt fields managed by Mongoose. In TypeScript mode the interface also lists createdAt: Date and updatedAt: Date, unless your JSON already has a key with that name.

Are all fields marked as required?

Not by default, since a JSON sample cannot show which fields are required. Turning the required switch On adds required: true to every field except nested schemas and arrays of objects; then remove it where a field is optional. Note that Mongoose's required validator rejects null, so a field that is null in your sample cannot stay required.

Is my data sent to a server?

No. The entire conversion runs in your browser. No data leaves your machine.