zig-pkl

zig-pkl

Zig 0.17 bindings for Pkl. Evaluate modules into Zig types, generate those types from Pkl schemas, and serve modules and resources from your own code.

zig fetch --save git+https://github.com/guanchzhou/zig-pkl#v0.1.1

Quick startInstallationAPI reference

Read config.pkl into a struct

const std = @import("std");
const zig_pkl = @import("zig_pkl");

const Config = struct {
    name: []const u8,
    port: u16,
    tags: []const []const u8,
};

pub fn main(init: std.process.Init) !void {
    const allocator = init.gpa;
    const io = init.io;

    // One manager owns one `pkl server` process.
    const manager = try zig_pkl.Manager.init(allocator, io, &.{ "pkl", "server" }, zig_pkl.Logger.noop);
    defer manager.deinit();

    // An evaluator holds the settings modules are evaluated with.
    var rejected: ?[]u8 = null;
    defer if (rejected) |text| allocator.free(text);
    const evaluator = try manager.createEvaluator(zig_pkl.Options.preconfigured(), &rejected);
    defer evaluator.close();

    const module_uri = try zig_pkl.uri.fromFile(allocator, io, "config.pkl");
    defer allocator.free(module_uri);

    var failure: ?[]u8 = null;
    defer if (failure) |text| allocator.free(text);
    const config = evaluator.evaluateInto(Config, allocator, .uri(module_uri), null, &failure) catch |err| {
        if (failure) |text| std.debug.print("{s}\n", .{text});
        return err;
    };
    defer zig_pkl.convert.freeInto(Config, allocator, config);

    std.debug.print("{s} listens on {d}\n", .{ config.name, config.port });
}

What the package covers

Typed and dynamic evaluation
Decode a module or an expression into Zig structs, unions, enums, slices, and maps, or walk the value tree.
Code generation
zig-pkl-gen writes Zig types from Pkl modules, including recursive classes and unions of unrelated types.
Readers
Serve modules and resources from Zig callbacks, or run your program as an external reader that Pkl starts.
Projects
Load PklProject settings and dependencies, with the same path rules on every supported Pkl release.
Concurrency
One server process shared by evaluators on any thread, with per-call timeouts and cancellation.
Restricted evaluation
Allow lists for modules and resources, an empty environment by default, and HTTP settings.

Measured against pkl-zig

Same run, same Pkl 0.32.2 executable, Apple M5, median of 31 rounds. Method, Linux results, and raw data.

  • 2.75×faster pkl-binary decoding, geometric mean of three cases
  • 245×fewer allocations decoding a configuration into a value tree
  • 7.76 msto start the server, evaluate, and shut down; pkl-zig 8.41 ms
  • 25.5 µsper evaluation on a running evaluator; pkl-zig 31.4 µs

Tested Pkl releases

CI runs the conformance suite, the integration tests, and every example against each of these releases on Linux, and Pkl 0.32.2 on linux-x86_64, linux-aarch64, macos-aarch64, windows-x86_64.

  • 0.25.3
  • 0.26.3
  • 0.27.2
  • 0.28.2
  • 0.29.1
  • 0.30.2
  • 0.31.1
  • 0.32.2

Some settings need a newer release. See version compatibility, or migrating from pkl-zig.