# Jump: lazy, allocation-free argv parsing in Zig

**URL:** <https://ziggit.dev/t/jump-lazy-allocation-free-argv-parsing-in-zig/13617>\
**Category:** Showcase\
**Tags:** cli\
**Created:** [December 22, 2025, 6:49pm UTC](https://ziggit.dev/t/jump-lazy-allocation-free-argv-parsing-in-zig/13617 "2025-12-22T18:49:51Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![nour](https://ziggit.dev/user_avatar/ziggit.dev/nour/32/10166_2.png) [@nour](https://ziggit.dev/u/nour)\
**Post date:** [December 22, 2025, 6:49pm UTC](https://ziggit.dev/t/jump-lazy-allocation-free-argv-parsing-in-zig/13617/1 "2025-12-22T18:49:51Z")

</div>

Hi,

I’m sharing **`jump`** , a small Zig library for parsing `argv` with a very explicit, low-level approach.

It started as a personal project to explore argument parsing but:

- without upfront schemas
- without forced structs
- without allocation
- without a single-pass “parse everything” model

Instead, `jump` lets you jump between targeted arguments lazily, using independent cursors that can be copied, rewound, or consumed on demand.

## Key Ideas

- getopt-like syntax, including chained short flags (`-abc`)
- lazy parsing: only parse what you ask for
- no allocation, no rewriting or reordering of argv
- multiple independent “jumpers”
- optional upfront validation
- explicit error handling with contextual debug hints
- supports subcommands

## Scope

**`jump`** is intentionally **not** a framework in which the user evolves, but rather just a set of composable primitives for people who want full control over how and when arguments are interpreted.

The whole library fits in ~350 lines and is heavily covered by tests.  
It’s meant for people who like `getopt`-style control and don’t want a black box.

## Peek

There is a demo step!

```sh
zig build demo

```

However, to give an idea right here (errors are printed to stdout as this is a snippet from the demo, which does it on purpose):

```zig
var iterator = try std.process.argsWithAllocator(std.heap.page_allocator); // the allocator is never used on POSIX, once on windows...
var myOpt = jump.Over(ArgIterator).init(iterator, 'v', &.{ "verbose", "ver" }, .forbidden, "get useful debug output");

while (myOpt.next()) |opt| {
    // The character returned is a count **per arg**'-v' returns 1 '-vvv' returns 3
    if (opt) |val| try out.print("\t'v' count in same chain: {d}\n", .{val[0]}) else break;
} else |err| {
    switch (err) { // For now there is only one possible error, but switching protects agains future additions...
        jump.LocalParsingError.ForbiddenValue => try out.print("{any}, hint: {s}, {any}\n", .{ err, myOpt.diag.debug_hint }),
        jump.LocalParsingError.MissingValue => unreachable, // the flag was declared with Level.forbidden
    }
}

```

Repo: [GitHub - megaNour/jump: lazy, allocation-free argv parsing in Zig](https://github.com/megaNour/jump)

Feedback welcome!
