Zig System Calls

Cross-platform system calls and file I/O with Bun's enhanced error handling

✨ The solution you've been looking for

Verified
Tested and verified by our team
86326 Stars

Guides using bun.sys for system calls and file I/O in Zig. Use when implementing file operations instead of std.fs or std.posix.

zig system-calls file-io cross-platform bun error-handling syscalls posix
Repository

See It In Action

Interactive preview & real-world examples

Live Demo
Skill Demo Animation

AI Conversation Simulator

See how users interact with this skill

User Prompt

I need to write a file utility in Zig that handles errors gracefully and works on both Windows and Linux. Show me how to read and write files using bun.sys.

Skill Processing

Analyzing request...

Agent Response

Complete file I/O implementation using bun.sys.File with proper error handling and cross-platform compatibility

Quick Start (3 Steps)

Get up and running in minutes

1

Install

claude-code skill install zig-system-calls

claude-code skill install zig-system-calls
2

Config

3

First Trigger

@zig-system-calls help

Commands

CommandDescriptionRequired Args
@zig-system-calls cross-platform-file-operationsImplement robust file reading/writing that works consistently across Windows and Unix-like systemsNone
@zig-system-calls advanced-error-handlingHandle system call errors with detailed context including errno, syscall information, and automatic EINTR retryNone
@zig-system-calls directory-operations-and-iterationPerform directory traversal and manipulation with proper cross-platform abstractionsNone

Typical Use Cases

Cross-platform File Operations

Implement robust file reading/writing that works consistently across Windows and Unix-like systems

Advanced Error Handling

Handle system call errors with detailed context including errno, syscall information, and automatic EINTR retry

Directory Operations and Iteration

Perform directory traversal and manipulation with proper cross-platform abstractions

Overview

System Calls & File I/O in Zig

Use bun.sys instead of std.fs or std.posix for cross-platform syscalls with proper error handling.

bun.sys.File (Preferred)

For most file operations, use the bun.sys.File wrapper:

 1const File = bun.sys.File;
 2
 3const file = switch (File.open(path, bun.O.RDWR, 0o644)) {
 4    .result => |f| f,
 5    .err => |err| return .{ .err = err },
 6};
 7defer file.close();
 8
 9// Read/write
10_ = try file.read(buffer).unwrap();
11_ = try file.writeAll(data).unwrap();
12
13// Get file info
14const stat = try file.stat().unwrap();
15const size = try file.getEndPos().unwrap();
16
17// std.io compatible
18const reader = file.reader();
19const writer = file.writer();

Complete Example

 1const File = bun.sys.File;
 2
 3pub fn writeFile(path: [:0]const u8, data: []const u8) File.WriteError!void {
 4    const file = switch (File.open(path, bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, 0o664)) {
 5        .result => |f| f,
 6        .err => |err| return err.toError(),
 7    };
 8    defer file.close();
 9
10    _ = switch (file.writeAll(data)) {
11        .result => {},
12        .err => |err| return err.toError(),
13    };
14}

Why bun.sys?

Aspectbun.sysstd.fs/std.posix
Return TypeMaybe(T) with detailed ErrorGeneric error union
WindowsFull support with libuv fallbackLimited/POSIX-only
Error Infoerrno, syscall tag, path, fderrno only
EINTRAutomatic retryManual handling

Error Handling with Maybe(T)

bun.sys functions return Maybe(T) - a tagged union:

 1const sys = bun.sys;
 2
 3// Pattern 1: Switch on result/error
 4switch (sys.read(fd, buffer)) {
 5    .result => |bytes_read| {
 6        // use bytes_read
 7    },
 8    .err => |err| {
 9        // err.errno, err.syscall, err.fd, err.path
10        if (err.getErrno() == .AGAIN) {
11            // handle EAGAIN
12        }
13    },
14}
15
16// Pattern 2: Unwrap with try (converts to Zig error)
17const bytes = try sys.read(fd, buffer).unwrap();
18
19// Pattern 3: Unwrap with default
20const value = sys.stat(path).unwrapOr(default_stat);

Low-Level File Operations

Only use these when bun.sys.File doesn’t meet your needs.

Opening Files

 1const sys = bun.sys;
 2
 3// Use bun.O flags (cross-platform normalized)
 4const fd = switch (sys.open(path, bun.O.RDONLY, 0)) {
 5    .result => |fd| fd,
 6    .err => |err| return .{ .err = err },
 7};
 8defer fd.close();
 9
10// Common flags
11bun.O.RDONLY, bun.O.WRONLY, bun.O.RDWR
12bun.O.CREAT, bun.O.TRUNC, bun.O.APPEND
13bun.O.NONBLOCK, bun.O.DIRECTORY

Reading & Writing

 1// Single read (may return less than buffer size)
 2switch (sys.read(fd, buffer)) {
 3    .result => |n| { /* n bytes read */ },
 4    .err => |err| { /* handle error */ },
 5}
 6
 7// Read until EOF or buffer full
 8const total = try sys.readAll(fd, buffer).unwrap();
 9
10// Position-based read/write
11sys.pread(fd, buffer, offset)
12sys.pwrite(fd, data, offset)
13
14// Vector I/O
15sys.readv(fd, iovecs)
16sys.writev(fd, iovecs)

File Info

1sys.stat(path)      // Follow symlinks
2sys.lstat(path)     // Don't follow symlinks
3sys.fstat(fd)       // From file descriptor
4sys.fstatat(fd, path)
5
6// Linux-only: faster selective stat
7sys.statx(path, &.{ .size, .mtime })

Path Operations

 1sys.unlink(path)
 2sys.unlinkat(dir_fd, path)
 3sys.rename(from, to)
 4sys.renameat(from_dir, from, to_dir, to)
 5sys.readlink(path, buf)
 6sys.readlinkat(fd, path, buf)
 7sys.link(T, src, dest)
 8sys.linkat(src_fd, src, dest_fd, dest)
 9sys.symlink(target, dest)
10sys.symlinkat(target, dirfd, dest)
11sys.mkdir(path, mode)
12sys.mkdirat(dir_fd, path, mode)
13sys.rmdir(path)

Permissions

1sys.chmod(path, mode)
2sys.fchmod(fd, mode)
3sys.fchmodat(fd, path, mode, flags)
4sys.chown(path, uid, gid)
5sys.fchown(fd, uid, gid)

Closing File Descriptors

Close is on bun.FD:

1fd.close();  // Asserts on error (use in defer)
2
3// Or if you need error info:
4if (fd.closeAllowingBadFileDescriptor(null)) |err| {
5    // handle error
6}

Directory Operations

1var buf: bun.PathBuffer = undefined;
2const cwd = try sys.getcwd(&buf).unwrap();
3const cwdZ = try sys.getcwdZ(&buf).unwrap();  // Zero-terminated
4sys.chdir(path, destination)

Directory Iteration

Use bun.DirIterator instead of std.fs.Dir.Iterator:

 1var iter = bun.iterateDir(dir_fd);
 2while (true) {
 3    switch (iter.next()) {
 4        .result => |entry| {
 5            if (entry) |e| {
 6                const name = e.name.slice();
 7                const kind = e.kind;  // .file, .directory, .sym_link, etc.
 8            } else {
 9                break;  // End of directory
10            }
11        },
12        .err => |err| return .{ .err = err },
13    }
14}

Socket Operations

Important: bun.sys has limited socket support. For network I/O:

  • Non-blocking sockets: Use uws.Socket (libuwebsockets) exclusively
  • Pipes/blocking I/O: Use PipeReader.zig and PipeWriter.zig

Available in bun.sys:

1sys.setsockopt(fd, level, optname, value)
2sys.socketpair(domain, socktype, protocol, nonblocking_status)

Do NOT use bun.sys for socket read/write - use uws.Socket instead.

Other Operations

 1sys.ftruncate(fd, size)
 2sys.lseek(fd, offset, whence)
 3sys.dup(fd)
 4sys.dupWithFlags(fd, flags)
 5sys.fcntl(fd, cmd, arg)
 6sys.pipe()
 7sys.mmap(...)
 8sys.munmap(memory)
 9sys.access(path, mode)
10sys.futimens(fd, atime, mtime)
11sys.utimens(path, atime, mtime)

Error Type

1const err: bun.sys.Error = ...;
2err.errno      // Raw errno value
3err.getErrno() // As std.posix.E enum
4err.syscall    // Which syscall failed (Tag enum)
5err.fd         // Optional: file descriptor
6err.path       // Optional: path string

Key Points

  • Prefer bun.sys.File wrapper for most file operations
  • Use low-level bun.sys functions only when needed
  • Use bun.O.* flags instead of std.os.O.*
  • Handle Maybe(T) with switch or .unwrap()
  • Use defer fd.close() for cleanup
  • EINTR is handled automatically in most functions
  • For sockets, use uws.Socket not bun.sys

What Users Are Saying

Real feedback from the community

Environment Matrix

Dependencies

Bun runtime environment
Zig compiler with Bun integration

Framework Support

Bun.sys ✓ (recommended) Compatible with std.io interfaces ✓

Context Window

Token Usage ~3K-8K tokens for typical system programming tasks

Security & Privacy

Information

Author
oven-sh
Updated
2026-01-30
Category
scripting