How to Validate JSON in JavaScript (With Code Examples)
"Validating JSON" means different things at different depths. Sometimes you only need to know the string parses; sometimes you need to know it parses and contains the fields your code is about to read; sometimes you need a formal contract. Here are all three levels, with working code.
Level 1: syntax validation with JSON.parse
JavaScript's built-in parser is the validator. If the string is not legal JSON, it throws:
function isValidJSON(text) {
try {
JSON.parse(text);
return true;
} catch {
return false;
}
}
Usually you want the parsed value and the error detail, not just a boolean:
function parseJSON(text) {
try {
return { ok: true, data: JSON.parse(text) };
} catch (err) {
return { ok: false, error: err.message }; // includes line/column in modern engines
}
}
Modern V8 and Firefox include the line and column in the error message, which makes debugging large payloads far less painful. For an instant no-code check, paste the payload into our JSON validator.
Level 2: structural validation
Syntactically valid JSON can still be the wrong shape — "hello" and [] are both valid JSON documents. After parsing, check what your code actually depends on:
const result = parseJSON(text);
if (!result.ok) throw new Error("Bad JSON: " + result.error);
const user = result.data;
if (typeof user !== "object" || user === null) throw new Error("Expected an object");
if (typeof user.id !== "number") throw new Error("Missing numeric 'id'");
if (typeof user.name !== "string") throw new Error("Missing string 'name'");
Two classic pitfalls: typeof null === "object", so always add the null check; and Array.isArray() is the correct test for arrays, because typeof [] === "object" too.
Level 3: schema validation
Hand-written checks scale badly past a handful of fields. JSON Schema lets you declare the contract once, and a library like Ajv enforces it:
import Ajv from "ajv";
const schema = {
type: "object",
required: ["id", "name"],
properties: {
id: { type: "integer", minimum: 1 },
name: { type: "string", minLength: 1 },
email: { type: "string" }
},
additionalProperties: false
};
const validate = new Ajv().compile(schema);
if (!validate(data)) console.log(validate.errors);
For TypeScript codebases, Zod offers the same idea with inferred static types, so the validated shape and the compile-time type can never drift apart.
Which level do you need?
- Level 1 — anything user-pasted or hand-edited, before you touch it.
- Level 2 — every external API response: parse, then check the two or three fields you use.
- Level 3 — public API inputs, webhook payloads, and any boundary where bad data has expensive consequences.
The universal rule: never trust unparsed input, and never assume a successful parse implies a correct shape. The five extra lines of checking are always cheaper than the production incident.