JSON Parsing in Every Language: JavaScript, Python, Go, Java, and More

February 11, 2026

JSON (JavaScript Object Notation) is the universal data interchange format of modern software development. Whether you are building a REST API, reading a configuration file, or passing messages between microservices, you will need to parse JSON. Every mainstream programming language has a built-in or standard library for it, but the APIs, idioms, and pitfalls differ wildly from one language to the next.

This guide gives you production-ready JSON parsing patterns in eight languages: JavaScript, Python, Go, Java, PHP, Ruby, Rust, and C#. For each one we cover basic parsing and serialization, error handling, working with nested objects and arrays, and mapping JSON to custom types. After the language sections, we cover common pitfalls that apply everywhere and finish with performance tips.

⚙ Before you start: If you are debugging malformed JSON right now, paste it into our JSON Formatter to auto-fix indentation and spot syntax errors, or run it through the JSON Validator for a line-by-line error report.

1. JavaScript — JSON.parse and JSON.stringify

JavaScript has native JSON support built into every runtime (browsers, Node.js, Deno, Bun). The two core functions live on the global JSON object.

Basic Parsing and Serialization

// Parse a JSON string into a JavaScript object
const data = JSON.parse('{"name": "Alice", "age": 30}');
console.log(data.name); // "Alice"

// Serialize a JavaScript object into a JSON string
const json = JSON.stringify({ name: "Alice", age: 30 });
console.log(json); // '{"name":"Alice","age":30}'

// Pretty-print with 2-space indentation
const pretty = JSON.stringify(data, null, 2);

Error Handling

JSON.parse throws a SyntaxError if the input is not valid JSON. Always wrap it in a try/catch when parsing untrusted input:

function safeParse(text) {
  try {
    return { data: JSON.parse(text), error: null };
  } catch (err) {
    return { data: null, error: err.message };
  }
}

const result = safeParse('{"broken: true}');
if (result.error) {
  console.error("Invalid JSON:", result.error);
}

Nested Objects and Arrays

const response = JSON.parse(`{
  "users": [
    {"id": 1, "name": "Alice", "roles": ["admin", "editor"]},
    {"id": 2, "name": "Bob", "roles": ["viewer"]}
  ],
  "meta": {"total": 2, "page": 1}
}`);

// Access nested data
console.log(response.users[0].roles[1]); // "editor"
console.log(response.meta.total);         // 2

// Optional chaining for safety
console.log(response.users?.[5]?.name);   // undefined (no crash)

Reviver and Replacer Functions

The second argument to JSON.parse is a reviver that can transform values during parsing. JSON.stringify accepts a replacer as its second argument:

// Reviver: auto-convert ISO date strings to Date objects
const withDates = JSON.parse(
  '{"created": "2026-02-11T10:00:00Z"}',
  (key, value) => {
    if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
      return new Date(value);
    }
    return value;
  }
);
console.log(withDates.created instanceof Date); // true

// Replacer: strip sensitive fields during serialization
const user = { name: "Alice", password: "secret", email: "a@b.com" };
const safe = JSON.stringify(user, (key, value) => {
  if (key === "password") return undefined;
  return value;
}, 2);
⚙ Try it: Paste deeply nested API responses into our JSON Viewer to explore the tree visually, or use the JSON Path Finder to get the exact accessor path (like $.users[0].roles[1]).

2. Python — The json Module

Python's standard library includes the json module. The two main functions are json.loads (parse a string) and json.dumps (serialize to a string). For files, use json.load and json.dump (no trailing "s").

Basic Parsing and Serialization

import json

# Parse JSON string to Python dict
data = json.loads('{"name": "Alice", "age": 30}')
print(data["name"])  # Alice

# Serialize Python dict to JSON string
text = json.dumps({"name": "Alice", "age": 30})
print(text)  # {"name": "Alice", "age": 30}

# Pretty-print
pretty = json.dumps(data, indent=2, sort_keys=True)

# Read from / write to a file
with open("data.json") as f:
    data = json.load(f)

with open("output.json", "w") as f:
    json.dump(data, f, indent=2)

Error Handling

Invalid JSON raises json.JSONDecodeError (a subclass of ValueError):

import json

raw = '{"broken: true}'
try:
    data = json.loads(raw)
except json.JSONDecodeError as e:
    print(f"Parse error at line {e.lineno}, col {e.colno}: {e.msg}")
    # Parse error at line 1, col 16: Expecting ':' delimiter

Nested Objects and Arrays

import json

response = json.loads("""
{
  "users": [
    {"id": 1, "name": "Alice", "tags": ["admin", "editor"]},
    {"id": 2, "name": "Bob", "tags": ["viewer"]}
  ],
  "pagination": {"page": 1, "total_pages": 5}
}
""")

# Access nested data
print(response["users"][0]["tags"][1])   # editor
print(response["pagination"]["total_pages"])  # 5

# Safe access with .get()
print(response.get("missing_key", "default"))  # default

Custom Types with object_hook

You can map JSON objects directly to Python classes:

import json
from dataclasses import dataclass

@dataclass
class User:
    id: int
    name: str
    email: str

def user_hook(obj):
    if "id" in obj and "name" in obj and "email" in obj:
        return User(**obj)
    return obj

data = json.loads(
    '{"id": 1, "name": "Alice", "email": "alice@example.com"}',
    object_hook=user_hook
)
print(isinstance(data, User))  # True
print(data.name)               # Alice

# For serialization of custom objects, use a default function
def custom_encoder(obj):
    if isinstance(obj, User):
        return {"id": obj.id, "name": obj.name, "email": obj.email}
    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")

json.dumps(data, default=custom_encoder)

3. Go — encoding/json

Go's standard library provides encoding/json. Go's static type system means you either unmarshal into a concrete struct or into a generic map[string]interface{}.

Basic Parsing and Serialization

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email,omitempty"`
}

func main() {
    // Parse JSON into a struct
    raw := []byte(`{"name": "Alice", "age": 30}`)
    var user User
    err := json.Unmarshal(raw, &user)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println(user.Name) // Alice

    // Serialize struct to JSON
    output, err := json.Marshal(user)
    fmt.Println(string(output)) // {"name":"Alice","age":30}

    // Pretty-print
    pretty, _ := json.MarshalIndent(user, "", "  ")
    fmt.Println(string(pretty))
}

Error Handling

Go's json.Unmarshal returns an error rather than panicking. Check common error types:

raw := []byte(`{"broken: true}`)
var data map[string]interface{}
err := json.Unmarshal(raw, &data)
if err != nil {
    // Check for specific error types
    if syntaxErr, ok := err.(*json.SyntaxError); ok {
        fmt.Printf("Syntax error at byte offset %d\n", syntaxErr.Offset)
    } else if typeErr, ok := err.(*json.UnmarshalTypeError); ok {
        fmt.Printf("Type mismatch for field %s: expected %s\n",
            typeErr.Field, typeErr.Type)
    } else {
        fmt.Println("JSON error:", err)
    }
}

Nested Objects and Dynamic JSON

// Nested structs map directly to nested JSON
type APIResponse struct {
    Users []User `json:"users"`
    Meta  struct {
        Total int `json:"total"`
        Page  int `json:"page"`
    } `json:"meta"`
}

// For dynamic or unknown JSON, use map[string]interface{}
var dynamic map[string]interface{}
json.Unmarshal(raw, &dynamic)

// Type assertions required for nested access
users := dynamic["users"].([]interface{})
first := users[0].(map[string]interface{})
fmt.Println(first["name"]) // Alice

// json.RawMessage lets you defer parsing of a field
type Envelope struct {
    Type    string          `json:"type"`
    Payload json.RawMessage `json:"payload"`
}

var env Envelope
json.Unmarshal(raw, &env)
// Now decide how to unmarshal env.Payload based on env.Type

Streaming with json.Decoder

import "os"

// Decode from an io.Reader (file, HTTP body, etc.)
file, _ := os.Open("data.json")
defer file.Close()

decoder := json.NewDecoder(file)
var user User
err := decoder.Decode(&user)

// Encode to an io.Writer
encoder := json.NewEncoder(os.Stdout)
encoder.SetIndent("", "  ")
encoder.Encode(user)

4. Java — Jackson and Gson

Java does not include a JSON parser in the core language. The two most popular libraries are Jackson (fasterxml) and Gson (Google). Both are mature, well-tested, and handle virtually every use case.

Jackson — Basic Parsing

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;

ObjectMapper mapper = new ObjectMapper();

// Parse into a POJO
String json = "{\"name\": \"Alice\", \"age\": 30}";
User user = mapper.readValue(json, User.class);
System.out.println(user.getName()); // Alice

// Parse into a tree (JsonNode) for dynamic access
JsonNode root = mapper.readTree(json);
System.out.println(root.get("name").asText());  // Alice
System.out.println(root.get("age").asInt());     // 30

// Serialize to JSON
String output = mapper.writeValueAsString(user);

// Pretty-print
String pretty = mapper.writerWithDefaultPrettyPrinter()
                      .writeValueAsString(user);

Jackson — POJO Definition

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private String name;
    private int age;

    @JsonProperty("email_address")
    private String email;

    // Constructors, getters, setters
    public User() {}
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

Jackson — Error Handling

import com.fasterxml.jackson.core.JsonProcessingException;

try {
    User user = mapper.readValue(invalidJson, User.class);
} catch (JsonProcessingException e) {
    System.err.println("JSON parse error: " + e.getOriginalMessage());
    System.err.println("Location: line " + e.getLocation().getLineNr()
                     + ", column " + e.getLocation().getColumnNr());
}

Jackson — Nested Objects, Arrays, and Generics

import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
import java.util.Map;

// Parse an array of users
String jsonArray = "[{\"name\":\"Alice\"},{\"name\":\"Bob\"}]";
List<User> users = mapper.readValue(jsonArray,
    new TypeReference<List<User>>() {});

// Parse a nested response wrapper
public class ApiResponse<T> {
    private T data;
    private Map<String, Object> meta;
    // getters/setters
}

ApiResponse<List<User>> response = mapper.readValue(json,
    new TypeReference<ApiResponse<List<User>>>() {});

Gson — Quick Comparison

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;

Gson gson = new GsonBuilder().setPrettyPrinting().create();

// Parse
User user = gson.fromJson("{\"name\": \"Alice\", \"age\": 30}", User.class);

// Serialize
String json = gson.toJson(user);

// Parse a List
Type listType = new TypeToken<List<User>>(){}.getType();
List<User> users = gson.fromJson(jsonArray, listType);

// Error handling
try {
    User u = gson.fromJson("not json", User.class);
} catch (JsonSyntaxException e) {
    System.err.println("Gson error: " + e.getMessage());
}
⚙ Validate your JSON schema: If your Java code expects a specific structure, define a schema and test payloads against it with our JSON Schema Validator.

5. PHP — json_decode and json_encode

PHP has had built-in JSON functions since version 5.2. The two primary functions are json_decode and json_encode.

Basic Parsing and Serialization

<?php
// Parse JSON string (returns object by default)
$data = json_decode('{"name": "Alice", "age": 30}');
echo $data->name; // Alice

// Parse as associative array (pass true as second argument)
$data = json_decode('{"name": "Alice", "age": 30}', true);
echo $data['name']; // Alice

// Serialize to JSON
$json = json_encode(['name' => 'Alice', 'age' => 30]);
echo $json; // {"name":"Alice","age":30}

// Pretty-print
$pretty = json_encode($data, JSON_PRETTY_PRINT);

// Useful flags
$json = json_encode($data,
    JSON_PRETTY_PRINT |
    JSON_UNESCAPED_SLASHES |
    JSON_UNESCAPED_UNICODE
);

Error Handling

By default, json_decode returns null on failure and does not throw. Use JSON_THROW_ON_ERROR (PHP 7.3+) for exception-based handling:

<?php
// Traditional error checking
$data = json_decode('{"broken: true}');
if (json_last_error() !== JSON_ERROR_NONE) {
    echo "Error: " . json_last_error_msg();
    // Error: Syntax error
}

// Modern exception-based (PHP 7.3+)
try {
    $data = json_decode('{"broken: true}', true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
    echo "JSON error: " . $e->getMessage();
}

Nested Objects and Arrays

<?php
$response = json_decode('{
    "users": [
        {"id": 1, "name": "Alice", "roles": ["admin"]},
        {"id": 2, "name": "Bob", "roles": ["viewer"]}
    ],
    "meta": {"total": 2}
}', true);

// Access nested data
echo $response['users'][0]['roles'][0]; // admin
echo $response['meta']['total'];        // 2

// Null coalescing for safe access
echo $response['users'][5]['name'] ?? 'not found'; // not found

Custom Types

<?php
class User {
    public function __construct(
        public readonly int $id,
        public readonly string $name,
        public readonly string $email
    ) {}

    public static function fromJson(string $json): self {
        $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
        return new self($data['id'], $data['name'], $data['email']);
    }

    public function toJson(): string {
        return json_encode([
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
        ], JSON_THROW_ON_ERROR);
    }
}

$user = User::fromJson('{"id": 1, "name": "Alice", "email": "a@b.com"}');
echo $user->name; // Alice

6. Ruby — JSON.parse

Ruby's standard library includes the json gem. Require it and use JSON.parse and JSON.generate.

Basic Parsing and Serialization

require 'json'

# Parse JSON string to Hash
data = JSON.parse('{"name": "Alice", "age": 30}')
puts data['name'] # Alice

# Serialize Hash to JSON string
json = JSON.generate({ name: 'Alice', age: 30 })
puts json # {"name":"Alice","age":30}

# Pretty-print
pretty = JSON.pretty_generate(data)

# Shorthand with to_json (available on Hash, Array, etc.)
puts({ name: 'Alice' }.to_json)

# Parse from file
data = JSON.parse(File.read('data.json'))

# Write to file
File.write('output.json', JSON.pretty_generate(data))

Error Handling

require 'json'

begin
  data = JSON.parse('{"broken: true}')
rescue JSON::ParserError => e
  puts "JSON parse error: #{e.message}"
end

Nested Objects and Arrays

require 'json'

response = JSON.parse('{
  "users": [
    {"id": 1, "name": "Alice", "roles": ["admin", "editor"]},
    {"id": 2, "name": "Bob", "roles": ["viewer"]}
  ],
  "meta": {"total": 2, "page": 1}
}')

puts response['users'][0]['roles'][1] # editor
puts response['meta']['total']        # 2
puts response.dig('users', 0, 'name') # Alice (safe nested access)

Symbolize Keys and Custom Types

require 'json'

# Symbolize keys for cleaner access
data = JSON.parse('{"name": "Alice"}', symbolize_names: true)
puts data[:name] # Alice

# Map to a custom class
class User
  attr_reader :id, :name, :email

  def initialize(id:, name:, email:)
    @id = id
    @name = name
    @email = email
  end

  def self.from_json(json_string)
    h = JSON.parse(json_string, symbolize_names: true)
    new(**h)
  end

  def to_json(*args)
    { id: @id, name: @name, email: @email }.to_json(*args)
  end
end

user = User.from_json('{"id": 1, "name": "Alice", "email": "a@b.com"}')
puts user.name # Alice

7. Rust — serde_json

Rust's ecosystem uses serde (serialization/deserialization framework) together with serde_json for JSON. Add both to your Cargo.toml:

[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"

Basic Parsing and Serialization

use serde::{Deserialize, Serialize};
use serde_json;

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    age: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    email: Option<String>,
}

fn main() -> Result<(), serde_json::Error> {
    // Parse JSON into a typed struct
    let json = r#"{"name": "Alice", "age": 30}"#;
    let user: User = serde_json::from_str(json)?;
    println!("{}", user.name); // Alice

    // Serialize struct to JSON
    let output = serde_json::to_string(&user)?;
    println!("{}", output);

    // Pretty-print
    let pretty = serde_json::to_string_pretty(&user)?;
    println!("{}", pretty);

    Ok(())
}

Error Handling

use serde_json;

fn parse_safely(input: &str) {
    match serde_json::from_str::<serde_json::Value>(input) {
        Ok(value) => println!("Parsed: {}", value),
        Err(e) => {
            eprintln!("Parse error at line {}, column {}: {}",
                e.line(), e.column(), e);
        }
    }
}

// Specific struct parsing errors
let result: Result<User, _> = serde_json::from_str(r#"{"name": 42}"#);
match result {
    Err(e) => eprintln!("Type mismatch: {}", e),
    Ok(u) => println!("{:?}", u),
}

Dynamic JSON with serde_json::Value

use serde_json::{Value, json};

// Parse into a dynamic Value
let v: Value = serde_json::from_str(r#"{
    "users": [{"name": "Alice"}, {"name": "Bob"}],
    "count": 2
}"#)?;

// Access with indexing (returns Value::Null if missing)
println!("{}", v["users"][0]["name"]); // "Alice"
println!("{}", v["count"]);            // 2
println!("{}", v["missing"]);          // null

// Build JSON with the json! macro
let payload = json!({
    "name": "Alice",
    "scores": [95, 87, 92],
    "active": true
});

Nested Structs and Enums

#[derive(Debug, Serialize, Deserialize)]
struct ApiResponse {
    users: Vec<User>,
    meta: Meta,
}

#[derive(Debug, Serialize, Deserialize)]
struct Meta {
    total: usize,
    page: usize,
}

// Tagged enums for polymorphic JSON
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
enum Event {
    #[serde(rename = "click")]
    Click { x: i32, y: i32 },
    #[serde(rename = "keypress")]
    KeyPress { key: String },
}

// {"type": "click", "x": 100, "y": 200} -> Event::Click { x: 100, y: 200 }
⚙ Navigating complex JSON: When you receive a deeply nested API response and need to figure out the path to a field, paste it into our JSON Path Finder. Click any value to get the full access path.

8. C# — System.Text.Json

Since .NET Core 3.0, C# includes System.Text.Json as a high-performance, built-in JSON library. It is the recommended choice for new projects, replacing the older Newtonsoft.Json (Json.NET).

Basic Parsing and Serialization

using System.Text.Json;

// Define a model class
public record User(string Name, int Age, string? Email = null);

// Parse JSON into an object
string json = "{\"Name\": \"Alice\", \"Age\": 30}";
User? user = JsonSerializer.Deserialize<User>(json);
Console.WriteLine(user?.Name); // Alice

// Serialize to JSON
string output = JsonSerializer.Serialize(user);
Console.WriteLine(output);

// Pretty-print with options
var options = new JsonSerializerOptions { WriteIndented = true };
string pretty = JsonSerializer.Serialize(user, options);

// Case-insensitive property matching (common for web APIs)
var webOptions = new JsonSerializerOptions {
    PropertyNameCaseInsensitive = true
};
User? u = JsonSerializer.Deserialize<User>(
    "{\"name\": \"Alice\", \"age\": 30}", webOptions);

Error Handling

using System.Text.Json;

try {
    var data = JsonSerializer.Deserialize<User>("not json");
} catch (JsonException ex) {
    Console.Error.WriteLine($"JSON error: {ex.Message}");
    Console.Error.WriteLine($"Path: {ex.Path}");
    Console.Error.WriteLine($"Line: {ex.LineNumber}, Byte: {ex.BytePositionInLine}");
}

Nested Objects and Arrays

using System.Text.Json;
using System.Collections.Generic;

public record ApiResponse(
    List<User> Users,
    MetaInfo Meta
);

public record MetaInfo(int Total, int Page);

string json = @"{
    ""Users"": [
        {""Name"": ""Alice"", ""Age"": 30},
        {""Name"": ""Bob"", ""Age"": 25}
    ],
    ""Meta"": {""Total"": 2, ""Page"": 1}
}";

var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var response = JsonSerializer.Deserialize<ApiResponse>(json, options);
Console.WriteLine(response?.Users[0].Name); // Alice
Console.WriteLine(response?.Meta.Total);    // 2

Dynamic JSON with JsonDocument and JsonNode

using System.Text.Json;
using System.Text.Json.Nodes;

// JsonDocument (read-only, high performance)
using var doc = JsonDocument.Parse(json);
JsonElement root = doc.RootElement;
string name = root.GetProperty("Users")[0].GetProperty("Name").GetString()!;

// JsonNode (.NET 6+, mutable, more flexible)
JsonNode? node = JsonNode.Parse(json);
string? firstName = node?["Users"]?[0]?["Name"]?.GetValue<string>();
Console.WriteLine(firstName); // Alice

// Modify and re-serialize
node!["Users"]![0]!["Name"] = "Charlie";
Console.WriteLine(node.ToJsonString());

Custom Converters and Naming Policies

using System.Text.Json;
using System.Text.Json.Serialization;

// Use camelCase for JSON property names (matching JS conventions)
var options = new JsonSerializerOptions {
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    WriteIndented = true
};

// Custom attribute for property naming
public class Product {
    [JsonPropertyName("product_name")]
    public string Name { get; set; } = "";

    [JsonIgnore]
    public string InternalCode { get; set; } = "";

    public decimal Price { get; set; }
}

Common JSON Pitfalls (All Languages)

Regardless of which language you use, certain JSON pitfalls trip up developers repeatedly. Here are the ones to watch for.

Trailing Commas

JSON does not allow trailing commas. This is valid JavaScript but invalid JSON:

// INVALID JSON - will fail in every parser
{
  "name": "Alice",
  "age": 30,
}

// VALID JSON
{
  "name": "Alice",
  "age": 30
}

This is the single most common JSON syntax error. It happens frequently when you add items to arrays or objects and forget to remove the last comma. Our JSON Validator will flag the exact line and column where a trailing comma appears.

Single Quotes

JSON requires double quotes for all strings and keys. Single quotes are not valid:

// INVALID - single quotes
{'name': 'Alice'}

// VALID - double quotes only
{"name": "Alice"}

Python developers are especially susceptible to this because Python's repr() uses single quotes. When logging dictionaries, always use json.dumps() rather than str().

NaN, Infinity, and Undefined

JSON has no representation for NaN, Infinity, -Infinity, or undefined. Different languages handle this differently:

// JavaScript: JSON.stringify silently converts or drops
JSON.stringify({ a: NaN, b: Infinity, c: undefined })
// Result: {"a":null,"b":null}
// Note: "c" is dropped entirely, NaN/Infinity become null

# Python: json.dumps raises ValueError by default
import json
json.dumps(float('nan'))  # ValueError
json.dumps(float('nan'), allow_nan=True)  # "NaN" (non-standard!)

// Go: encoding/json returns an error for NaN/Inf
// Use custom MarshalJSON to handle these cases

Date and Time Handling

JSON has no native date type. Dates are typically represented as ISO 8601 strings ("2026-02-11T10:30:00Z") or Unix timestamps (1771063800). Every language requires explicit conversion:

// JavaScript - Date objects serialize to ISO strings
JSON.stringify({ created: new Date() })
// {"created":"2026-02-11T10:30:00.000Z"}

// But parsing does NOT auto-convert back:
const obj = JSON.parse('{"created":"2026-02-11T10:30:00Z"}');
typeof obj.created // "string" (NOT a Date!)
// You need a reviver function (shown in the JavaScript section above)

# Python - datetime is not JSON serializable by default
import json
from datetime import datetime
json.dumps({"created": datetime.now()})  # TypeError!
# Solution: use .isoformat() or a default function
json.dumps({"created": datetime.now()}, default=str)

Large Numbers and Precision Loss

JavaScript uses 64-bit floating point (IEEE 754) for all numbers. Integers larger than Number.MAX_SAFE_INTEGER (2^53 - 1 = 9007199254740991) will lose precision:

// This is dangerous:
JSON.parse('{"id": 9007199254740993}')
// { id: 9007199254740992 } -- WRONG! Silently rounded!

// Solutions:
// 1. Use string IDs in your API
// 2. Use BigInt (requires custom reviver/replacer)
// 3. Use a BigInt-aware parser like json-bigint

This is a real-world problem. Twitter famously sends tweet IDs as both id (number) and id_str (string) specifically because of this issue.

Comments in JSON

Standard JSON does not support comments. If you need comments in configuration files, consider JSON5, JSONC (JSON with Comments, used by VS Code), YAML, or TOML:

// INVALID JSON - comments are not allowed
{
  // This is a comment
  "name": "Alice" /* inline comment */
}

// If you control the format, use JSONC or JSON5 instead
// VS Code's settings.json uses JSONC

Encoding Issues (Unicode and BOM)

JSON must be encoded in UTF-8 (RFC 8259). Watch out for:

⚙ Debugging tool: Paste broken JSON into our JSON Formatter to see exactly where the syntax error is. It highlights the problematic line and suggests fixes for common issues like trailing commas and single quotes.

Performance Tips

For most applications, JSON parsing is not a bottleneck. But when you are processing millions of records, handling real-time data streams, or running on resource-constrained devices, performance matters. Here are practical tips across languages.

1. Use Streaming Parsers for Large Files

Loading an entire multi-gigabyte JSON file into memory at once is a recipe for OOM (Out of Memory) errors. Use streaming/incremental parsers instead:

# Python: ijson for streaming large files
import ijson

with open("huge_file.json", "rb") as f:
    for item in ijson.items(f, "users.item"):
        process(item)  # Processes one user at a time

// Go: json.Decoder reads tokens incrementally
decoder := json.NewDecoder(reader)
for decoder.More() {
    var item User
    decoder.Decode(&item)
    process(item)
}

// Java: Jackson's JsonParser for token-level streaming
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(inputStream);
while (parser.nextToken() != null) {
    // Process tokens incrementally
}

2. Reuse Parsers and Serializers

Creating new parser/serializer instances is expensive in some languages. Reuse them:

// Java: Reuse ObjectMapper (it is thread-safe)
// DO THIS:
private static final ObjectMapper MAPPER = new ObjectMapper();
// NOT THIS:
ObjectMapper mapper = new ObjectMapper(); // in every method call

// C#: Reuse JsonSerializerOptions
private static readonly JsonSerializerOptions Options = new() {
    PropertyNameCaseInsensitive = true,
    WriteIndented = true
};
// Pass Options to every Serialize/Deserialize call

// Go: json.Decoder/Encoder are cheap, but for hot paths consider
// pre-allocating buffers or using jsoniter/sonic

3. Parse Only What You Need

If you only need a few fields from a large JSON object, do not deserialize the entire thing:

// Go: Use json.RawMessage to defer parsing
type Envelope struct {
    Type    string          `json:"type"`
    Payload json.RawMessage `json:"payload"` // Not parsed yet
}

// Rust: #[serde(skip)] fields you don't need
#[derive(Deserialize)]
struct PartialUser {
    name: String,
    // Other fields are ignored automatically with default settings
}

// JavaScript: Destructure immediately after parsing
const { name, email } = JSON.parse(hugeJsonString);
// The entire object is still parsed, but you can GC the rest

# Python: Use JSONPath or jq for extraction
# Or parse into dict and access only needed keys

4. Consider Alternative Libraries

The standard library JSON parsers prioritize correctness and compatibility. If you need raw speed, consider these alternatives:

5. Use Source Generation (C# and Rust)

Avoid runtime reflection by generating serialization code at compile time:

// C# (.NET 6+): Source generators eliminate reflection overhead
[JsonSerializable(typeof(User))]
[JsonSerializable(typeof(List<User>))]
internal partial class AppJsonContext : JsonSerializerContext {}

// Usage:
var user = JsonSerializer.Deserialize(json, AppJsonContext.Default.User);

// Rust: serde's derive macros already generate code at compile time
// This is the default behavior -- no extra setup needed
#[derive(Serialize, Deserialize)]
struct User { name: String, age: u32 }

6. Minimize Allocations

String allocations are a common bottleneck in JSON parsing. Tips to reduce them:

7. Benchmark Your Specific Workload

JSON parsing performance depends heavily on the shape of your data: deeply nested vs. flat, many small strings vs. few large ones, numeric-heavy vs. string-heavy. Always benchmark with your actual data rather than relying on generic benchmarks.

Quick Reference Table

Language Parse Serialize Error Type
JavaScript JSON.parse(str) JSON.stringify(obj) SyntaxError
Python json.loads(str) json.dumps(obj) JSONDecodeError
Go json.Unmarshal() json.Marshal() *json.SyntaxError
Java (Jackson) mapper.readValue() mapper.writeValueAsString() JsonProcessingException
Java (Gson) gson.fromJson() gson.toJson() JsonSyntaxException
PHP json_decode(str) json_encode(val) JsonException
Ruby JSON.parse(str) JSON.generate(obj) JSON::ParserError
Rust serde_json::from_str() serde_json::to_string() serde_json::Error
C# JsonSerializer.Deserialize() JsonSerializer.Serialize() JsonException

Conclusion

JSON parsing is one of those tasks that seems trivially easy until you hit edge cases: trailing commas from a code generator, NaN values from a math library, 64-bit integer IDs that lose precision, or date strings that need to become real date objects. Every language handles these differently, and knowing the specific API, error types, and pitfalls for your language will save you hours of debugging.

The key takeaways:

⚙ DevToolbox JSON Tools: We have a full suite of free JSON tools to help with your daily workflow:

Related Resources

JSON Formatter
Format, validate, and beautify JSON
JSON Validator
Line-by-line JSON validation with error details
JSON Viewer
Interactive tree view for complex JSON
JSON Path Finder
Click any value to get the full path
JSON Schema Validator
Test payloads against JSON Schema
10 JSON Debugging Tips
Practical tips for debugging JSON in APIs