Back to Blog
    October 14, 20267 min read

    How to Parse JSON in JavaScript: JSON.parse(), fetch() and Error Handling

    JavaScript
    JSON
    Tutorial

    Parsing JSON in JavaScript is a daily task for every web developer. This guide covers everything from the basics of JSON.parse() to fetching remote JSON, handling errors correctly, and typing the result in TypeScript — with copy-paste examples for each pattern.

    The Basics: JSON.parse()

    JSON.parse() converts a JSON string into a JavaScript value. It accepts any valid JSON: object, array, string, number, boolean, or null.

    const json = '{"name": "Alice", "age": 30, "active": true}';
    const user = JSON.parse(json);
    
    console.log(user.name);   // "Alice"
    console.log(user.age);    // 30
    console.log(user.active); // true

    Always Use try/catch

    JSON.parse() throws a SyntaxError if the input isn't valid JSON. Never call it without error handling on untrusted input:

    function safeJsonParse(text) {
      try {
        return { data: JSON.parse(text), error: null };
      } catch (e) {
        return { data: null, error: e.message };
      }
    }
    
    const { data, error } = safeJsonParse('not valid json');
    if (error) {
      console.error('Parse failed:', error);
    } else {
      console.log(data);
    }

    Fetching JSON from an API

    The Fetch API returns a Response object. Call .json() on it — which internally calls JSON.parse() — to get the parsed value:

    async function getUser(id) {
      const response = await fetch(`https://api.example.com/users/${id}`);
    
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
    
      const user = await response.json(); // JSON.parse() internally
      return user;
    }
    
    // Usage
    try {
      const user = await getUser(42);
      console.log(user);
    } catch (e) {
      console.error('Failed to fetch user:', e.message);
    }

    Check response.ok before .json()

    Fetch only rejects on network failures, not HTTP errors (404, 500). Always check response.ok (true when status is 200-299) before calling response.json(), otherwise you might parse an error HTML page as JSON and get a confusing SyntaxError.

    The Reviver Function

    Pass a reviver as the second argument to transform values during parsing — the most common use case is parsing ISO date strings into real Date objects:

    const json = '{"name":"Alice","createdAt":"2026-10-14T08:00:00.000Z"}';
    
    const user = JSON.parse(json, (key, value) => {
      if (key === 'createdAt') return new Date(value);
      return value;
    });
    
    console.log(user.createdAt instanceof Date); // true
    console.log(user.createdAt.getFullYear());   // 2026

    JSON.stringify() — The Reverse

    Serialize a JavaScript value back to a JSON string with JSON.stringify(). The optional third argument sets indentation for pretty-printing:

    const user = { name: 'Alice', age: 30, createdAt: new Date() };
    
    // Compact (for APIs)
    const compact = JSON.stringify(user);
    
    // Pretty (for logging / files)
    const pretty = JSON.stringify(user, null, 2);
    console.log(pretty);
    // {
    //   "name": "Alice",
    //   "age": 30,
    //   "createdAt": "2026-10-14T08:00:00.000Z"
    // }

    TypeScript: Typing Parsed JSON

    JSON.parse() returns any in TypeScript. Cast or validate to get type safety:

    // Option 1: Type assertion (no runtime check)
    interface User {
      id: number;
      name: string;
      email: string;
    }
    
    const user = JSON.parse(jsonString) as User;
    
    // Option 2: Runtime validation with Zod (recommended)
    import { z } from 'zod';
    
    const UserSchema = z.object({
      id: z.number(),
      name: z.string(),
      email: z.string().email(),
    });
    
    type User = z.infer<typeof UserSchema>;
    
    function parseUser(raw: string): User {
      const data = JSON.parse(raw);
      return UserSchema.parse(data); // throws ZodError if invalid
    }
    
    // Option 3: Safe parse (no throw)
    const result = UserSchema.safeParse(JSON.parse(raw));
    if (result.success) {
      console.log(result.data.name);
    } else {
      console.error(result.error.issues);
    }

    Parsing JSON from Node.js — Files and Streams

    import { readFileSync, createReadStream } from 'fs';
    
    // Small file — synchronous (blocks event loop)
    const config = JSON.parse(readFileSync('./config.json', 'utf8'));
    
    // Or with require (also synchronous, cached)
    const pkg = require('./package.json');
    
    // Large file — streaming with a library
    import JSONStream from 'JSONStream';
    import { pipeline } from 'stream/promises';
    
    const stream = createReadStream('./large.json');
    stream
      .pipe(JSONStream.parse('rows.*'))
      .on('data', (row) => console.log(row));

    Common Pitfalls

    PitfallFix
    Trailing comma in object/arrayUse a linter; JSON forbids trailing commas
    Single-quoted keys or valuesJSON requires double quotes everywhere
    NaN or Infinity in numbersReplace with null or use a replacer
    Forgetting await on response.json()Always await — it returns a Promise
    Not checking response.okCheck before calling .json()
    Parsing JSON twice (double-encode)Parse once; log intermediate values to check

    Validate before parsing

    If you're unsure whether your JSON is valid, paste it into the JSON Validator first. It pinpoints the exact line and character position of every syntax error, saving you debugging time.