mongoui
Schema·July 2, 2026·6 min read

How to enforce a schema in MongoDB with JSON Schema validation

MongoDB will reject writes that do not match a shape you define with $jsonSchema. Here is a real validator, how to add it without breaking existing data, and the one thing $jsonSchema does not do that everyone expects: set default values.

Arctic Glass illustration for How to enforce a schema in MongoDB with JSON Schema validation

MongoDB has a flexible schema, and $jsonSchema validation is how you make it firm once you have decided on a shape. You attach a rule set to the collection, and MongoDB rejects any write that does not match. It is the difference between a schema your documents happen to share and one the database will not let them break. Here is a real validator, how to roll it out without locking yourself out of your own data, and the feature everyone expects that does not exist.

A validator that actually does something

Define the required fields and their types, and attach it at creation:

db.createCollection("users", {
  validator: { $jsonSchema: {
    bsonType: "object",
    required: ["email", "createdAt", "role"],
    properties: {
      email:     { bsonType: "string", pattern: "^.+@.+$" },
      createdAt: { bsonType: "date" },
      role:      { enum: ["admin", "member", "guest"] },
      age:       { bsonType: "int", minimum: 0 }
    }
  } }
})

Now an insert without an email, or with role: "superuser", or with age as the string "30", is rejected before it lands. The schema validation docs list every keyword, but bsonType, required, enum, pattern, and minimum cover most of what you will reach for.

Roll it out without breaking production

Turning on strict validation over a collection full of legacy data is how you cause the incident you were trying to prevent. Two knobs make the rollout safe.

validationLevel decides which documents are checked. strict (the default) checks every insert and update. moderate only checks new documents and updates to documents that were already valid, so your messy historical records are left alone until something touches them.

validationAction decides what happens on a miss. error rejects the write. warn allows it but logs a warning. The safe sequence is: start with warn, watch the logs, clean up what fails, then switch to error.

db.runCommand({
  collMod: "users",
  validator: { $jsonSchema: { /* ... */ } },
  validationLevel: "moderate",
  validationAction: "warn"      // observe first, enforce later
})

collMod is also how you add validation to a collection that already exists, no recreate required.

The one it does not do: default values

Here is the expectation that trips people, and the reason "json schema default value" is a search at all. JSON Schema as a spec has a default keyword. MongoDB's $jsonSchema ignores it. Validation checks the shape of a document; it does not fill in missing fields. Put a default in your validator and nothing populates, MongoDB simply does not use it.

Defaults live somewhere else:

  • In your application code, when you build the document.
  • In your ODM (Mongoose and friends apply schema defaults before the write).
  • In an upsert, with $setOnInsert, so a field is set only when the document is first created.
db.users.updateOne(
  { email: "sam@example.com" },
  { $setOnInsert: { role: "member", createdAt: new Date() } },
  { upsert: true }
)

Validation enforces that role is present and valid. Setting role when it is missing is a separate job, and it is yours.

Validate the shape, then keep watching it

Validation stops the next bad write, but it does not fix the documents already in the collection, and it does not catch drift in fields you did not think to constrain. That is the other half of schema work: analyzing your schema to find the type splits and missing fields that predate the validator, and designing the shape in the first place is MongoDB schema design.

mongoui's Schema doctor samples a collection and reports its real field shapes and type drift, which is how you decide what the validator should require and confirm nothing already violates it before you switch to error. It runs on your machine, so your documents never leave your network. Define the shape, roll it out with warn then error, and set your defaults where defaults actually live.

Frequently asked questions

How does JSON Schema validation work in MongoDB?

You attach a $jsonSchema validator to a collection, defining required fields and their types. MongoDB then checks every write against it and rejects the ones that do not match. Add it at creation with createCollection, or to an existing collection with collMod.

Does MongoDB $jsonSchema support default values?

No. This surprises people coming from JSON Schema drafts that include default. MongoDB's $jsonSchema validates the shape of a document; it does not populate missing fields. Set defaults in your application, in your ODM, or with $setOnInsert on an upsert.

How do I add validation to an existing MongoDB collection?

Use collMod: db.runCommand({ collMod: "users", validator: { $jsonSchema: {...} }, validationLevel: "moderate" }). moderate only enforces the rules on new documents and on updates to already-valid documents, so a collection with legacy data is not locked down all at once.

What is the difference between validationAction error and warn in MongoDB?

error rejects a non-matching write. warn allows the write but logs a warning. Start with warn while you clean up existing data and confirm nothing legitimate is failing, then switch to error to enforce.