History

  • Who: Created by Niels Lohmann (GitHub: nlohmann).
  • Why: To provide a modern, intuitive C++ JSON library that feels natural — using STL containers and operator overloading so JSON reads like native C++ code.
  • When: First released around 2013, now one of the most starred C++ repos on GitHub.

Introduction

What is it?

  • A single-header JSON library for C++11 and later.
  • Include just json.hpp — no build system changes needed.
  • GitHub: nlohmann/json

Advantages

  • Single header — drop json.hpp into your project and go.
  • Intuitive syntax — JSON objects map naturally to C++ types.
  • Full JSON spec compliance (RFC 8259).
  • Supports custom type serialization/deserialization.
  • STL-compatible iterators and algorithms.

Disadvantages

  • Slower than simpler parsers (simdjson, RapidJSON) for high-throughput use.
  • Large header can increase compile times.
  • Not ideal for embedded/constrained environments.

Installation & Setup

Single Header (Easiest)

# Download json.hpp from GitHub releases
wget https://github.com/nlohmann/json/releases/latest/download/json.hpp
#include "json.hpp"
using json = nlohmann::json;

vcpkg

vcpkg install nlohmann-json

CMake (FetchContent)

include(FetchContent)
FetchContent_Declare(json
    URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp
)
FetchContent_MakeAvailable(json)
target_link_libraries(MyApp nlohmann_json::nlohmann_json)

Core Concepts

Creating JSON

#include <nlohmann/json.hpp>
using json = nlohmann::json;
 
// From literals
json j = {
    {"name", "Alice"},
    {"age", 30},
    {"active", true},
    {"scores", {95, 87, 92}},
    {"address", {
        {"city", "Mumbai"},
        {"zip", "400001"}
    }}
};
 
std::cout << j.dump(4); // pretty print with 4-space indent

Accessing Values

json j = {{"name", "Bob"}, {"age", 25}, {"scores", {10, 20, 30}}};
 
std::string name = j["name"];       // "Bob"
int age = j["age"];                 // 25
int first = j["scores"][0];         // 10
 
// Safe access with .value() — returns default if key missing
std::string city = j.value("city", "Unknown"); // "Unknown"
 
// Check existence
if (j.contains("name")) { ... }
if (j.count("age")) { ... }

Parsing JSON Strings

std::string raw = R"({"id": 1, "title": "Hello", "tags": ["cpp", "json"]})";
 
json j = json::parse(raw);
 
std::cout << j["title"];        // Hello
std::cout << j["tags"][0];      // cpp
 
// Parse with error handling
try {
    json bad = json::parse("{invalid}");
} catch (const json::parse_error& e) {
    std::cout << "Parse error: " << e.what();
}

Serialization (to string)

json j = {{"x", 1}, {"y", 2}};
 
std::string compact = j.dump();      // {"x":1,"y":2}
std::string pretty  = j.dump(2);     // pretty with 2-space indent
 
// To stream
std::cout << j << "\n";
std::ofstream file("out.json");
file << j;

Reading from File

#include <fstream>
 
std::ifstream file("config.json");
json config;
file >> config;
 
std::string host = config["server"]["host"];
int port = config["server"]["port"];

Custom Type Serialization

struct Point {
    double x, y;
};
 
// Define to_json and from_json in the same namespace as Point
void to_json(json& j, const Point& p) {
    j = json{{"x", p.x}, {"y", p.y}};
}
 
void from_json(const json& j, Point& p) {
    j.at("x").get_to(p.x);
    j.at("y").get_to(p.y);
}
 
// Usage
Point pt{3.0, 4.0};
json j = pt;                    // calls to_json
std::cout << j.dump();          // {"x":3.0,"y":4.0}
 
Point pt2 = j.get<Point>();     // calls from_json
std::cout << pt2.x;             // 3.0

STL Container Integration

// vector
std::vector<int> v = {1, 2, 3};
json j = v;                          // [1,2,3]
std::vector<int> v2 = j.get<std::vector<int>>();
 
// map
std::map<std::string, int> m = {{"a", 1}, {"b", 2}};
json jm = m;                         // {"a":1,"b":2}
 
// Iterate JSON object
for (auto& [key, val] : j.items()) {
    std::cout << key << ": " << val << "\n";
}
 
// Iterate JSON array
for (const auto& item : j) {
    std::cout << item << "\n";
}

JSON Pointer & Patch

json j = {{"a", {{"b", {{"c", 42}}}}}};
 
// JSON Pointer (RFC 6901)
std::cout << j["/a/b/c"_json_pointer]; // 42
 
// Modify via pointer
j["/a/b/c"_json_pointer] = 99;
 
// JSON Patch (RFC 6902)
json patch = json::parse(R"([
    {"op": "replace", "path": "/a/b/c", "value": 100},
    {"op": "add", "path": "/a/b/d", "value": "new"}
])");
json patched = j.patch(patch);

More Learn