A simple, direct Zig library for reading and writing ZON (Zig Object Notation) files.
📚 Documentation | API Reference | Quick Start | Allocators | Contributing
A document-based ZON (Zig Object Notation) library for Zig, designed for configuration file editing, dynamic access, and data manipulation. Unlike std.zon which parses ZON into typed structures, zon.zig maintains an in-memory document tree that you can query, modify, and serialize.
⭐️ If you find zon.zig useful, please give it a star! ⭐️
🔄 zon.zig vs std.zon (click to expand)
| Feature | zon.zig | std.zon |
|---|---|---|
| Approach | Document-based (DOM tree) | Type-based (deserialization) |
| Best For | Config editing, dynamic access | Type-safe parsing into structs |
| Modification | Full read/write/edit/merge | Read-only (serialize separately) |
| Path Access | Dot notation ("db.host") |
Direct field access |
| Dependencies | Custom parser (No Ast dependency) | Uses std.zig.Ast, Zoir |
| Stability | Independent of compiler internals | Tied to Zig compiler API |
| Special Values | NaN, Inf, -Inf support | Limited in some Zig versions |
Use zon.zig when:
- You need to edit and save configuration files programmatically.
- The structure isn't known at compile time or varies.
- You want advanced features like Deep Merge, Find & Replace, and Deep Equality.
- You need a lightweight parser that doesn't pull in
std.zig.Ast.
Use std.zon when:
- You know the structure at compile time and want static type safety.
- You're using
@importfor compile-time ZON values.
✨ Features of zon.zig (click to expand)
| Feature | Description |
|---|---|
| 📖 Simple API | Clean open, get, set, delete, save interface |
| 🔗 Path-Based Access | Use dot notation like "dependencies.foo.path" |
| 🏗️ Auto-Create Nested Objects | Missing intermediate paths are created automatically |
| 🔒 Type-Safe Getters | getString, getBool, getInt, getFloat, getNumber |
| 🛡️ No Panics | Missing paths return null, type mismatches return null |
| 🔧 Custom Parser | Does NOT depend on std.zig.Ast or compiler internals |
| 📝 Pretty Print | Formatted output with configurable indentation |
| 🔍 Find & Replace | Search and replace values throughout the document |
| 📋 Array Operations | Get length, elements, append to arrays |
| 🔄 Merge & Clone | Shallow & Deep Merge, Combine documents, Deep copy |
| 📏 Multi-line Strings | Full support for multi-line backslash syntax (\\) |
| ♾️ Special Floats | Support for inf, -inf, and nan values |
| ⚖️ Deep Equality | Deeply compare two ZON documents or values |
| 🖥️ Cross-Platform | Windows, Linux, macOS (32-bit and 64-bit) |
| 📦 Zero Dependencies | Built entirely on the Zig standard library |
| ⚡ High Performance | Efficient parsing and serialization |
| 🔄 Update Checker | Optional automatic update checking (can be disabled) |
| 📁 File Operations | Delete, copy, rename, check existence |
| 🧠 Memory Flexibility | Full support for GPA, Arena, and custom allocators |
| 🌐 JSON Interop | Import from and Export to standard JSON |
| 📏 Object Iterators | Programmatic iteration over key-value pairs and arrays |
| 🏗️ Flatten & Expand | Convert nested ZON to flat dot-notation maps |
| 🛡️ Integrity Suite | Stable Hashing (Order-independent) & Checksums |
| 📏 Size Metrics | Calculate byte size and compact size of documents |
| 🔍 Recursive Search | Find keys anywhere (find, findAll) |
| 🔁 Aliases | Use preferred naming (e.g., init/new, len/size) |
| 📂 File Key Utils | Move/Copy keys directly in files without full parsing |
| 📊 Diagnostic Errors | High-quality syntax error reporting with line/column |
📌 Prerequisites & Supported Platforms (click to expand)
| Requirement | Version | Notes |
|---|---|---|
| Zig | 0.15.0+ | Download from ziglang.org |
| Operating System | Windows 10+, Linux, macOS | Cross-platform support |
| Platform | 32-bit | 64-bit | ARM | Status |
|---|---|---|---|---|
| Windows | ✅ x86 | ✅ x86_64 | - | Full support |
| Linux | ✅ x86 | ✅ x86_64 | ✅ aarch64 | Full support |
| macOS | ✅ x86 | ✅ x86_64 | ✅ aarch64 (Apple Silicon) | Full support |
| Freestanding | ✅ x86 | ✅ x86_64 | ✅ aarch64, arm, riscv64 | Full support |
zig fetch --save https://github.com/muhammad-fiaz/zon.zig/archive/refs/tags/0.0.3.tar.gzor
for Nightly Installation, use this
zig fetch --save git+https://github.com/muhammad-fiaz/zon.zig.gitThen in your build.zig:
const zon_dep = b.dependency("zon", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zon", zon_dep.module("zon"));const std = @import("std");
const zon = @import("zon");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Optional: Disable update checking
zon.disableUpdateCheck();
// Create a new ZON document
var doc = zon.create(allocator);
defer doc.deinit();
// Set values
try doc.setString("name", "myapp");
try doc.setBool("private", true);
try doc.setInt("port", 8080);
// Nested paths - auto-creates intermediate objects
try doc.setString("dependencies.http.path", "../http");
// Read values
std.debug.print("Name: {s}\n", .{doc.getString("name").?});
// Save to file
try doc.saveAs("config.zon");
}zon.zig fully supports the build.zig.zon format:
.{
.name = .zon, // Identifier as value
.version = "0.0.3", // String
.fingerprint = 0xee480fa30d50cbf6, // Multi-bit hex handled as i128
.minimum_zig_version = "0.15.0",
.paths = .{ // Array of strings
"build.zig",
"build.zig.zon",
"src",
},
.dependencies = .{ // Nested objects
.http = .{
.url = "https://example.com",
.hash = "abc123",
},
},
}const source =
\\.{
\\ .name = .my_package,
\\ .version = "0.1.0",
\\ .paths = .{
\\ "build.zig",
\\ "src",
\\ },
\\}
;
var doc = try zon.parse(allocator, source);
defer doc.deinit();
// Read identifier value
const name = doc.getString("name"); // "my_package"
// Read array
const paths_len = doc.arrayLen("paths"); // 2
const first_path = doc.getArrayString("paths", 0); // "build.zig"var doc = zon.create(allocator);
defer doc.deinit();
try doc.setString("host1", "localhost");
try doc.setString("host2", "localhost");
try doc.setString("host3", "192.168.1.1");
// Find all paths containing "localhost"
const found = try doc.findString("localhost");
defer allocator.free(found);
// found.len == 2
// Replace all occurrences
const count = try doc.replaceAll("localhost", "production.example.com");
// count == 2
// Replace first occurrence only
const replaced = try doc.replaceFirst("old", "new");
// Replace last occurrence only
const replaced_last = try doc.replaceLast("old", "new");// Create array and append
try doc.setArray("items");
try doc.appendToArray("items", "first");
try doc.appendToArray("items", "second");
try doc.appendIntToArray("numbers", 42);
// Read array
const len = doc.arrayLen("items"); // 2
const elem = doc.getArrayString("items", 0); // "first"// Default 4-space indentation
const output = try doc.toString();
// Custom indentation
const two_space = try doc.toPrettyString(2);
// Compact (no indentation)
const compact = try doc.toCompactString();var base = zon.create(allocator);
try base.setString("name", "app");
try base.setInt("port", 8080);
var override = zon.create(allocator);
try override.setInt("port", 9000);
try override.setBool("debug", true);
// Merge override into base
try base.merge(&override); // Shallow merge
try base.mergeRecursive(&override); // Deep merge (merges nested objects)
// base now has port=9000, debug=true
// Deep equality
if (base.eql(&override)) { ... }
// Deep clone
var copy = try base.clone();
defer copy.deinit();| Function | Description |
|---|---|
zon.open(allocator, path) |
Open existing ZON file |
zon.create(allocator) |
Create new empty document |
zon.parse(allocator, source) |
Parse ZON from string |
zon.readFile(allocator, path) |
Read file into allocator-owned buffer |
zon.writeFileAtomic(allocator, path, data) |
Write data atomically (tmp + rename) |
zon.copyFile(source, dest, overwrite: bool) |
Copy a file (with optional overwrite) |
zon.moveFile(old, new, overwrite: bool) |
Move/rename file (with optional overwrite) |
zon.deleteFile(path) |
Delete a ZON file |
zon.fileExists(path) |
Check if file exists |
zon.disableUpdateCheck() |
Disable update checking |
| Method | Description |
|---|---|
getString(path) |
Get string value or null |
getBool(path) |
Get bool value or null |
getInt(path) |
Get integer value or null |
getUint(path) |
Get u64 value or null |
getFloat(path) |
Get float value or null |
getNumber(path) |
Get number as float or null |
toBool(path) |
Coerce value to boolean |
isNull(path) |
Check if value is null |
isNan(path) |
Check if value is NaN |
isInf(path) |
Check if value is Inf |
exists(path) |
Check if path exists |
getType(path) |
Get base type name |
getTypeName(path) |
Get precise type name |
| Method | Description |
|---|---|
setString(path, value) |
Set string value |
setBool(path, value) |
Set bool value |
setInt(path, value) |
Set integer value |
setFloat(path, value) |
Set float value |
setNull(path) |
Set value to null |
setObject(path) |
Set empty object |
setArray(path) |
Set empty array |
| Method | Description |
|---|---|
arrayLen(path) |
Get array length |
getArrayString(path, index) |
Get string at index |
getArrayElement(path, index) |
Get element at index |
getArrayBool(path, index) |
Get boolean element |
appendToArray(path, value) |
Append string to array |
appendIntToArray(path, value) |
Append int to array |
insertStringIntoArray(path, index, value) |
Insert string |
insertIntIntoArray(path, index, value) |
Insert integer |
removeFromArray(path, index) |
Remove from array |
indexOf(path, value) |
Find string index |
countAt(path) |
Count items/keys |
| Method | Description |
|---|---|
findString(needle) |
Find paths containing string |
findExact(needle) |
Find paths with exact match |
replaceAll(find, replace) |
Replace all occurrences |
replaceFirst(find, replace) |
Replace first occurrence |
replaceLast(find, replace) |
Replace last occurrence |
| Method | Description |
|---|---|
delete(path) |
Delete key, returns true if existed |
clear() |
Clear all data |
count() |
Get number of root keys |
keys() |
Get all root keys |
merge(other) |
Merge another document |
clone() |
Create a deep copy |
save() |
Save to original file path |
saveAs(path) |
Save to specified path |
saveAsAtomic(path) |
Atomically save to specified path (temporary file + rename) |
saveWithBackup(backup_ext) |
Save and create a backup of the previous file using the extension |
saveIfChanged() |
Only write when contents differ (normalizes trailing newline; returns bool) |
toString() |
Get formatted ZON string |
toCompactString() |
Get compact ZON string |
toPrettyString(indent) |
Get ZON with custom indent |
deinit() |
Free all resources |
close() |
Alias for deinit() |
The examples/ directory contains comprehensive examples:
- basic.zig - Core operations and getting started
- package_manifest.zig - Parsing build.zig.zon format
- find_replace.zig - Find and replace operations
- arrays.zig - Array operations
- pretty_print.zig - Pretty printing with different indentation
- merge_clone.zig - Merging and cloning documents
- config_management.zig - Configuration file management
- file_operations.zig - Atomic writes, backups, and file helpers
- identifier_values.zig - Identifier value parsing and usage
- nested_creation.zig - Creating deeply nested structures
- error_handling.zig - Examples of parse and file error handling
Added file helpers for safer file operations:
zon.readFile(path, allocator)- Read file contents into allocator-managed bufferzon.writeFileAtomic(path, contents)- Atomically write using a temporary file + renamezon.copyFile(src, dest, overwrite)- Copy file with optional overwritezon.moveFile(src, dest, overwrite)- Move/rename file with optional overwriteDocument.saveAsAtomic(path)- Save a document atomicallyDocument.saveWithBackup(path)- Save and create a.bakbackup of the previous fileDocument.saveIfChanged()- Only write when contents differ (normalizes trailing newline; returnstrueif a write occurred)
# Run tests
zig build test
# Build library
zig build
# Run example
zig build example
# Format code
zig fmt src/ examples/Full documentation: https://muhammad-fiaz.github.io/zon.zig/
Contributions are welcome! Please read CONTRIBUTING.md.
MIT License - see LICENSE.
- Documentation: https://muhammad-fiaz.github.io/zon.zig/
- Repository: https://github.com/muhammad-fiaz/zon.zig
- Issues: https://github.com/muhammad-fiaz/zon.zig/issues
- Releases: https://github.com/muhammad-fiaz/zon.zig/releases