Overview
The std.json module provides comprehensive JSON parsing and serialization capabilities conforming to RFC 8259. It offers both low-level token-based APIs and high-level functions for parsing JSON into Zig types.
High-Level API
parseFromSlice
pub fn parseFromSlice(
comptime T: type,
allocator: Allocator,
source: []const u8,
options: ParseOptions
) !Parsed(T)
Parses a JSON document from a string slice into a Zig value.
The Zig type to parse into.
Allocator for dynamic memory (strings, arrays, etc.).
Parsing configuration options.
A structure containing the parsed value and arena allocator. Call .deinit() to free.
Example:
const std = @import("std");
const User = struct {
name: []const u8,
age: u32,
active: bool = true,
};
var parsed = try std.json.parseFromSlice(
User,
allocator,
\"{\"name\": \"Alice\", \"age\": 30}",
.{}
);
defer parsed.deinit();
// Access the parsed value
const user = parsed.value;
std.debug.print("Name: {s}, Age: {}\n", .{user.name, user.age});
parseFromSliceLeaky
pub fn parseFromSliceLeaky(
comptime T: type,
allocator: Allocator,
source: []const u8,
options: ParseOptions
) !T
Parses JSON without managing cleanup. Caller must free all allocations manually.
stringify
pub fn stringify(
value: anytype,
options: StringifyOptions,
writer: *std.Io.Writer
) !void
Serializes a Zig value as JSON.
Example:
const User = struct { name: []const u8, age: u32 };
const user = User{ .name = "Bob", .age = 25 };
var list = std.ArrayList(u8).init(allocator);
defer list.deinit();
var writer = std.Io.Writer.Allocating.init(allocator);
defer writer.deinit();
try std.json.stringify(user, .{}, &writer.writer);
const json_string = writer.written();
// json_string is "{\"name\":\"Bob\",\"age\":25}"
Dynamic JSON Values
Value
pub const Value = union(enum) {
null,
bool: bool,
integer: i64,
float: f64,
number_string: []const u8,
string: []const u8,
array: Array,
object: ObjectMap,
};
Represents a dynamically-typed JSON value for runtime inspection.
Example:
var parsed = try std.json.parseFromSlice(
std.json.Value,
allocator,
\"{\"key\": [1, 2, 3], \"nested\": {\"flag\": true}}",
.{}
);
defer parsed.deinit();
const obj = parsed.value.object;
const array = obj.get("key").?.array;
const first = array.items[0].integer; // 1
const nested = obj.get("nested").?.object;
const flag = nested.get("flag").?.bool; // true
ObjectMap
pub const ObjectMap = std.StringArrayHashMapUnmanaged(Value);
A map type for JSON objects, preserving insertion order.
Array
pub const Array = std.ArrayListUnmanaged(Value);
A dynamic array for JSON arrays.
Low-Level Scanner API
Scanner
pub const Scanner = struct {
pub fn initCompleteInput(allocator: Allocator, source: []const u8) Scanner;
pub fn next(self: *Scanner) !Token;
pub fn deinit(self: *Scanner) void;
};
Low-level token scanner for streaming JSON parsing.
Example:
var scanner = std.json.Scanner.initCompleteInput(
allocator,
\"{\"foo\": 123}\n"
);
defer scanner.deinit();
const tok1 = try scanner.next(); // .object_begin
const tok2 = try scanner.next(); // .string with value "foo"
const tok3 = try scanner.next(); // .number with value "123"
const tok4 = try scanner.next(); // .object_end
const tok5 = try scanner.next(); // .end_of_document
Token
pub const Token = union(enum) {
object_begin,
object_end,
array_begin,
array_end,
string: []const u8,
number: []const u8,
true,
false,
null,
end_of_document,
};
Represents a single JSON token.
Stringify API
Stringify
pub const Stringify = struct {
writer: *std.Io.Writer,
options: Options,
pub const Options = struct {
whitespace: Whitespace = .minified,
pub const Whitespace = union(enum) {
minified,
indent_1,
indent_2,
indent_3,
indent_4,
indent_tab,
};
};
};
Low-level JSON writer for manual control.
Methods:
pub fn beginObject(self: *Stringify) !void;
pub fn endObject(self: *Stringify) !void;
pub fn beginArray(self: *Stringify) !void;
pub fn endArray(self: *Stringify) !void;
pub fn objectField(self: *Stringify, name: []const u8) !void;
pub fn write(self: *Stringify, value: anytype) !void;
Example:
var out = std.Io.Writer.Allocating.init(allocator);
defer out.deinit();
var writer = std.json.Stringify{
.writer = &out.writer,
.options = .{ .whitespace = .indent_2 },
};
try writer.beginObject();
try writer.objectField("name");
try writer.write("Alice");
try writer.objectField("items");
try writer.beginArray();
try writer.write(1);
try writer.write(2);
try writer.endArray();
try writer.endObject();
const json = out.written();
// {
// "name": "Alice",
// "items": [
// 1,
// 2
// ]
// }
Parse Options
ParseOptions
pub const ParseOptions = struct {
allocate: AllocWhen = .alloc_always,
duplicate_field_behavior: DuplicateFieldBehavior = .use_first,
ignore_unknown_fields: bool = false,
max_value_len: ?usize = default_max_value_len,
pub const AllocWhen = enum {
alloc_always,
alloc_if_needed,
};
pub const DuplicateFieldBehavior = enum {
use_first,
@"error",
use_last,
};
};
Controls when to allocate for strings. .alloc_always copies all strings; .alloc_if_needed may reference source.
How to handle duplicate object keys.
If true, ignore JSON fields that don’t match struct fields.
Maximum length for string/number tokens.
Validation
validate
pub fn validate(source: []const u8) !void
Validates that a string contains well-formed JSON.
Example:
try std.json.validate("{\"valid\": true}");
// Returns successfully
std.json.validate("{invalid}") catch |err| {
// err is std.json.Error.SyntaxError
};
fmt
pub fn fmt(value: anytype, options: Stringify.Options) Formatter(@TypeOf(value))
Returns a formatter that serializes a value using std.fmt integration.
Example:
const value = .{ .x = 10, .y = 20 };
std.debug.print("JSON: {f}\n", .{std.json.fmt(value, .{})});
// Prints: JSON: {"x":10,"y":20}
Error Types
Error
pub const Error = error{
UnexpectedEndOfInput,
InvalidNumber,
InvalidEscape,
InvalidUnicodeEscape,
InvalidTopLevel,
SyntaxError,
BufferUnderrun,
};
ParseError
pub const ParseError = error{
UnexpectedToken,
InvalidNumber,
Overflow,
InvalidEnumTag,
DuplicateField,
UnknownField,
MissingField,
LengthMismatch,
} || Error;