Skip to content

Merge & Clone ​

zon.zig supports merging documents together and creating deep copies.

Merging Documents ​

Use merge to combine two documents. Values from the source document overwrite existing values in the target.

zig
var base = zon.create(allocator);
defer base.deinit();

try base.setString("name", "myapp");
try base.setString("version", "1.0.0");
try base.setInt("port", 8080);

var override = zon.create(allocator);
defer override.deinit();

try override.setInt("port", 9000);
try override.setBool("debug", true);

// Merge override into base (Shallow at the root level)
try base.merge(&override);

// base now has:
// - name: "myapp" (unchanged)
// - version: "1.0.0" (unchanged)
// - port: 9000 (overwritten)
// - debug: true (added)

Recursive Merge ​

mergeRecursive combines nested structures (objects) instead of just overwriting the top-level keys. This is much more powerful for complex configurations.

zig
var base = try zon.parse(allocator, ".{ .db = .{ .port = 5432, .host = \"localhost\" } }");
defer base.deinit();

var override = try zon.parse(allocator, ".{ .db = .{ .port = 6000 } }");
defer override.deinit();

try base.mergeRecursive(&override);

// base now has:
// .db = .{ .port = 6000, .host = "localhost" }

Deep Equality ​

Use eql to check if two documents or values are deeply equivalent.

zig
if (base.eql(&override)) {
    std.debug.print("Full documents are identical\n", .{});
}

Use Cases ​

  • Configuration Layers: Merge environment-specific configs over base configs
  • Default Values: Create defaults, then merge user preferences
  • Incremental Updates: Apply patches to existing documents

Cloning Documents ​

Use clone to create an independent deep copy:

zig
var original = zon.create(allocator);
defer original.deinit();

try original.setString("name", "original");
try original.setInt("value", 100);

// Create deep copy
var copy = try original.clone();
defer copy.deinit();

// Modify the copy
try copy.setString("name", "copy");
try copy.setInt("value", 200);

// Original is unchanged
std.debug.print("Original: {s}, {d}\n", .{
    original.getString("name").?,
    original.getInt("value").?
});
// Output: Original: original, 100

std.debug.print("Copy: {s}, {d}\n", .{
    copy.getString("name").?,
    copy.getInt("value").?
});
// Output: Copy: copy, 200

Practical Example ​

zig
const std = @import("std");
const zon = @import("zon");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    zon.disableUpdateCheck();

    // Create base config
    var dev_config = zon.create(allocator);
    defer dev_config.deinit();

    try dev_config.setString("environment", "development");
    try dev_config.setString("database.host", "localhost");
    try dev_config.setInt("database.port", 5432);
    try dev_config.setString("database.name", "myapp_dev");
    try dev_config.setBool("debug", true);

    std.debug.print("Development config:\n", .{});
    const dev_str = try dev_config.toString();
    defer allocator.free(dev_str);
    std.debug.print("{s}\n\n", .{dev_str});

    // Clone for production
    var prod_config = try dev_config.clone();
    defer prod_config.deinit();

    // Create production overrides
    var prod_overrides = zon.create(allocator);
    defer prod_overrides.deinit();

    try prod_overrides.setString("environment", "production");
    try prod_overrides.setString("database.host", "db.example.com");
    try prod_overrides.setString("database.name", "myapp_prod");
    try prod_overrides.setBool("debug", false);

    // Merge overrides
    try prod_config.merge(&prod_overrides);

    std.debug.print("Production config:\n", .{});
    const prod_str = try prod_config.toString();
    defer allocator.free(prod_str);
    std.debug.print("{s}\n", .{prod_str});
}

Output:

Development config:
.{
    .database = .{
        .host = "localhost",
        .name = "myapp_dev",
        .port = 5432,
    },
    .debug = true,
    .environment = "development",
}

Production config:
.{
    .database = .{
        .host = "db.example.com",
        .name = "myapp_prod",
        .port = 5432,
    },
    .debug = false,
    .environment = "production",
}

Released under the MIT License.