Zig (programming language)
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these messages)
|
| Zig | |
|---|---|
| Paradigms | Multi-paradigm: imperative, concurrent, procedural, functional |
| Designed by | Andrew Kelley |
| First appeared | 8 February 2016[1] |
| Stable release | |
| Typing discipline | Static, strong, inferred, nominal, generic |
| Memory management | Manual |
| Implementation language | Zig |
| Platform | x86-64, ARM64, WebAssembly Tier 2: ARM, IA-32, RISC-V, MIPS64, POWERPC64, SPARC64, some tier-2 platforms have tier-1 support for standalone programs |
| OS | Cross-platform: Linux, macOS, FreeBSD, Windows |
| License | MIT |
| Filename extensions | .zig, .zir, .zigr, .zon |
| Website | ziglang |
| Influenced by | |
| C, C++, LLVM IR, Go, Rust [3][4][5][6][7][8][9][10] | |
Zig is a system programming language designed to be a general-purpose improvement to the C programming language.[11] It is free and open-source software, released under an MIT License on Codeberg, a source-code sharing platform.[12]
Differences with C relate to control flow, function calls, library imports, variable declaration and Unicode support. The language makes no use of macros or preprocessor instructions. Features adopted from modern languages include the addition of compile time generic programming data types, allowing functions to work on a variety of data, along with a small set of new compiler directives to allow access to the information about those types using reflection.[13] Zig requires manual memory management.[13] Features for low-level programming include packed structs, arbitrary-width integers[14] and multiple pointer types.[15]
Zig was designed by Andrew Kelley and first announced in 2016.[1] Development is funded by the Zig Software Foundation (ZSF) which receives corporate sponsorships as well as personal donations.[16][17]
Language
[edit]Goals
[edit]The primary goal of Zig is to be a better solution to the sorts of tasks that are currently solved with C. A primary concern in that respect is readability; Zig attempts to use existing concepts and syntax wherever possible, avoiding the addition of different syntax for similar concepts. Further, its goal is to be a language designed for "robustness, optimality and maintainability". The small and simple syntax is an important part of that maintainability, as one of the language's goals is to allow maintainers to debug code written in Zig without having to learn the intricacies of a language they might not be familiar with.[18] Even with these changes, Zig can compile into and against existing C code; C headers can be included in a Zig project and their functions called, and Zig code can be linked into C projects by including the compiler-built headers.[19]
Error handling is handled through error types and can be handled with catch or try. Generics are achieved through compile time code generation and accommodating a form of duck typing with the comptime directive.[citation needed]
Memory handling
[edit]Memory allocation in the Zig standard library follows the convention that allocation is handled through structs describing the action, as opposed to calling the memory management functions in libc. For instance, in C if one wants to write a function that makes a string containing multiple copies of another string, the function might look like this:
const char* repeat(const char* original, size_t times);
In the code, the function would examine the size of original and then malloc times that length to set aside memory for the string it will build. That malloc is invisible to the functions calling it; if they fail to later release the memory, a leak will occur. In Zig, this might be handled using a function like:
const Allocator = std.mem.Allocator;
fn repeat(allocator: Allocator, original: []const u8, times: usize) Allocator.Error![]const u8;
In this code, the allocator variable is passed a struct that describes what code should perform the allocation, and the repeat function returns either the resulting string or, using the optional type as indicated by the !, an Allocator.Error. By directly expressing the allocator as an input, memory allocation is never "hidden" within another function, it is always exposed to the API by the function that is ultimately calling for the memory to be allocated. No allocations are performed inside Zig’s standard library. Further, as the struct can point to anything, one can use alternative allocators, even ones written in the program. This can allow, for instance, small-object allocators that do not use the operating system functions that normally allocate an entire memory page.[20]
Optional types are an example of a language feature that offers general functionality while still being simple and generic. They do not have to be used to solve null pointer problems; they are also useful for any type of value where "no value" is an appropriate answer. Consider a function countTheNumberOfUsers that returns an integer, and an integer variable, theCountedUsers that holds the result. In many languages, a magic number would be placed in theCountedUsers to indicate that countTheNumberOfUsers has not yet been called, while many implementations would just set it to zero. In Zig, this could be implemented as an var theCountedUsers: ?i32 = null which sets the variable to a clear "not been called" value.[20]
Another more general feature of Zig that also helps manage memory problems is the concept of defer, which marks some code to be performed at the end of a scope no matter what happens, including possible runtime errors. If a particular function allocates some memory and then disposes of it when the operation is complete, one can add a line to defer a free to ensure it is released no matter what happens.[20]
The Zig standard library avoids hidden allocations. Allocation is not managed in the language directly. Instead, heap access is done via the standard library, explicitly.[21]
Direct interaction with C
[edit]Zig promotes a gradual approach to portability by providing direct interoperability of Zig code with C code, allowing code from one language to call code from the other. Since 0.16.0, this is implemented through Zig's build system, by enabling C libraries to be defined within the build.zig file of the Zig project, to enable for the Zig code to import the C libraries through the use of the @import keyword.[22]
For inclusion of C code in a primarily Zig project, this is typically implemented in the build.zig file, in a similar fashion to the following example (note that this example is only of the relevant code):
const translate_c = b.addTranslateC(.{
.root_source_file = b.path("src/cheaders.h"),
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "example",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.optimize = optimize,
.target = target,
.imports = &.{
.{
.name = "c",
.module = translate_c.createModule(),
},
},
}),
});
The C headers can then be called in Zig code with the following code:
const c = @import("c");
c.exampleFunction();
This is in line with how Zig imports its own libraries, similarly with the @import directive, typically in this fashion:
const std = @import("std");
For the alternate method of utilising and calling Zig code inside a primarily C program, this is more difficult than the aforementioned, as the Zig build system focusses on a Zig-based environment. However, it is a similar setup, as the Zig build system is still utilised for such a purpose in most scenarios. As C code naturally uses C header files (.h) and macros, all Zig declarations, such as functions, would need to be expressed either within header files or extern declarations, as would be done for C interoperability with programming languages other than Zig. The following code is an example for a C project which uses Zig code, where the shared declarations between C and Zig code are contained within an extern.h file:
const sharedheader = b.addTranslateC(.{
.root_source_file = b.path("./src/extern.h"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
const zig_code = b.addLibrary(.{
.name = "zigcodelib",
.linkage = .static,
.root_module = b.createModule(.{
.root_source_file = b.path("src/zigcode.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.imports = &.{
.{ .name = "flags.h", .module = sharedheader.createModule() },
},
}),
});
const main_c_module = b.addModule("main", .{
.target = target,
.optimize = mode,
.link_libc = true,
});
main_c_module.addCSourceFile(.{
.file = b.path("src/main.c"),
.flags = &.{ "-Wall", "-pedantic" },
});
const exe = b.addExecutable(.{
.name = "example",
.root_module = main_c_module,
});
exe.root_module.linkLibrary(zig_code);
b.installArtifact(zig_code);
b.installArtifact(exe);
Zig 0.16.0 deprecated @cImport, going forward C Translation will be handled via the Build System instead of using the @cImport language builtin, which has been 'deleted' from the language. Additionally the release deprecated std.Build.Step.TranslateC in favour using an explicit package dependency of the official translate-c package, which is the same implementation as the previous build step version with additional configuration options.[22]
Prior to 0.16.0, the system used for C interoperability did not use the Zig build system, and instead used a @cImport directive only used for calling C code. This directive would often wrap an additional @cInclude directive, which mirrored the #include macro that would be seen within C code. In these prior versions of Zig, C libraries are imported in the following manner:
const c = @cImport(@cInclude("soundio/soundio.h"));
This Zig code would be functionally equivalent to the following C code with the main difference being that the library is accessed through calls to the constant identifier c, as seen in the current 0.16.0 example.
#include <soundio/soundio.h>
The Zig code would then be able to call functions from soundio library in the same manner as calling functions from other Zig code, As Zig uses new data types that are explicitly defined, unlike C’s more generic int and float, a small number of directives are used to move data between the C and Zig types, including @intCast and @ptrCast.[20] This is notably different from the current implementations, as Zig code would directly be able to import code from system header files, whereas the current implementation only allows for Zig code to import C code from local libraries defined within the users code.
Compile time evaluation
[edit]Zig can evaluate sections of code at compile time instead of runtime using the comptime keyword. Running code at compile time provides functionality similar to macros and conditional compilation, without the use of a separate preprocessor language.[23]
Types become first-class citizens at compile time, allowing compile-time duck typing,[24] which Zig uses to implement generic types. The example below declares a generic linked list:
fn LinkedList(comptime T: type) type;
The function takes the type T and produces a concrete linked-list type based on T.
Compiler
[edit]The Zig compiler is self-hosted, meaning it is written in the Zig programming language.[citation needed] Prior to version 0.10 Zig was compiled using LLVM based compiler.
Zig also includes a C and C++ compiler, and can be used with either or both languages by leveraging with the commands zig cc and zig c++,[25] providing many headers including the C standard library (libc) and C++ Standard Library (libcxx) for many different platforms. This allows Zig’s cc and c++ sub-commands to act as cross compilers out of the box (similarly to Clang).[26][27]
Zig treats cross-compiling as a first-class use-case of the language.[13] This means any Zig compiler can compile runnable binaries for any of its target platforms, of which there are dozens. These include not only widely-used modern systems like ARM and x86-64, but also PowerPC, SPARC, MIPS, RISC-V, LoongArch64 and even the IBM z/Architectures (S390). The toolchain can compile to any of these targets without installing additional software, all the needed support is in the basic system.[20] The experimental support is also provided for less known platforms like AMD and Nvidia GPUs or PlayStation 4 and 5 (with various degree of support).
Cross-compilation is also available for variety of the operating systems (mostly desktop ones). Popular UNIX-like ones and Windows are officially supported (and documented), but (minimal) applications can and have been made for Android (with Android NDK) or iOS.[citation needed]
The LLVM backend is the default for most targets, except for SPIR-V, and x86-64[28] (although this is currently just in Debug mode). Zig also supports their self-hosted backend which can be enabled by using -fno-llvm.
History
[edit]Kelley began to develop a digital audio workstation,[29] but he found "Go interoperability with C libraries difficult, and found the garbage collector caused audio delays. He tried C++, but found that small mistakes led to memory corruption bugs that took weeks to fix. He tried Rust but "really struggled to write code that would satisfy Rust's rules," and spent a month trying to make font rendering work."[30]
The name Zig was picked using a script that generated random combinations of letters starting with the letter z.[31]
The previous bootstrapping compiler, written in Zig and C++ using LLVM as a back-end,[32][33] supporting many of its native targets,[34] was removed in version 0.11. Newer versions of Zig use a prebuilt WebAssembly version of Zig to bootstrap itself.
On 26 November 2025, Zig development migrated from GitHub to Codeberg, citing GitHub's declining reliability under Microsoft ownership, particularly due to poor use of Generative AI on the platform, as a primary reason for this change.[35][36] One cited example of the platform's declining reliability was the apparent unreliability and delays towards the fixing of bugs in GitHub's CI platform, GitHub Actions.[35][36] In addition, the Zig development team had concerns with the Generative AI direction of GitHub, which was in contrast to the Zig project's policy against Generative AI.[37] In 2026, Codeberg would introduce a policy against Generative AI[38][39], similar to the policy of the Zig project.
Packages
[edit]Version 0.11.0 bundles an experimental package manager, but no official package repository is available. Instead a package is simply a URL that points to a compressed file, or a Git repository. Each package ideally includes a standard build.zig file (that the Zig compiler uses by convention to compile the source code) and a build.zig.zon file containing metadata with name and version of the package.[citation needed]
Examples
[edit]Hello World example |
|---|
const std = @import("std");
const File = std.Io.File;
pub fn main(init: std.process.Init) !void {
_ = try File.stdout().writeStreamingAll(init.io, "Hello, World!\n");
}
|
Generic linked list example |
|---|
const std = @import("std");
const FormatOptions = std.fmt.FormatOptions;
const stdout = std.io.getStdOut().writer();
fn LinkedList(comptime T: type) type {
return struct {
const Self = @This();
pub const Node = struct {
next: ?*Node = null,
data: T,
};
first: ?*Node = null,
pub fn prepend(
list: *Self,
new_node: *Node,
) void {
new_node.next = list.first;
list.first = new_node;
}
pub fn format(
list: Self,
comptime fmt: []const u8,
options: FormatOptions,
out_stream: anytype,
) !void {
try out_stream.writeAll("( ");
var it = list.first;
while (it) |node| : (it = node.next) {
try std.fmt.formatType(
node.data,
fmt,
options,
out_stream,
1,
);
try out_stream.writeAll(" ");
}
try out_stream.writeAll(")");
}
};
}
pub fn main() !void {
const ListU32 = LinkedList(u32);
var list = ListU32{};
var node1 = ListU32.Node{ .data = 1 };
var node2 = ListU32.Node{ .data = 2 };
var node3 = ListU32.Node{ .data = 3 };
list.prepend(&node1);
list.prepend(&node2);
list.prepend(&node3);
try stdout.print("{}\n", .{list});
try stdout.print("{b}\n", .{list});
}
Output: ( 3 2 1 )
( 11 10 1 )
|
String repetition with allocator example |
|---|
const std = @import("std");
const ArenaAllocator = std.heap.ArenaAllocator;
const Allocator = std.mem.Allocator;
fn repeat(
allocator: Allocator,
original: []const u8,
times: usize,
) Allocator.Error![]u8 {
const buffer = try allocator.alloc(
u8,
original.len * times,
);
for (0..times) |i| {
std.mem.copyForwards(
u8,
buffer[(original.len * i)..],
original,
);
}
return buffer;
}
pub fn main() !void {
var arena = ArenaAllocator.init(
std.heap.page_allocator,
);
defer arena.deinit();
const allocator = arena.allocator();
const original = "Hello ";
const repeated = try repeat(
allocator,
original,
3,
);
std.debug.print("{s}\n", .{repeated});
}
Output: Hello Hello Hello
|
Notable projects
[edit]Projects that use (or have previously used) Zig include:
- Bun, a JavaScript and TypeScript runtime originally written in Zig (until v1.3.14) and rewritten in Rust (starting with v1.4.0) in 2026, using Safari's JavaScriptCore virtual machine.[40]
- TigerBeetle, a financial transaction database[41][42]
- Ghostty, a GPU accelerated terminal emulator[43]
References
[edit]Citations
[edit]- 1 2 Kelley, Andrew (8 February 2016). "Introduction to the Zig Programming Language". andrewkelley.me. Retrieved 8 November 2020.
- ↑ "0.16.0 Released". 14 April 2026. Retrieved 14 April 2026.
- ↑ "What are the pros and cons of Zig vs Rust? I see Zig mentioned more and more her... | Hacker News".
- ↑ "Why Zig when There is Already C++, D, and Rust? ⚡ Zig Programming Language".
- ↑ "No surprises on any system: Q&A with Loris Cro of Zig - Stack Overflow". 2 October 2023.
- ↑ "Zig's New Relationship with LLVM | Hacker News".
- ↑ "What's Zig got that C, Rust and Go don't have? (With Loris Cro)". YouTube. 15 November 2023.
- ↑ "Why Zig when there is already C++, D, and Rust? | Hacker News".
- ↑ "Overview ⚡ Zig Programming Language".
- ↑ "After a day of programming in Zig". 29 December 2023. Archived from the original on 11 February 2025. Retrieved 31 December 2024.
- ↑ "Taking the warts off C, with Andrew Kelley, creator of the Zig programming language". Sourcegraph. 19 October 2021. Archived from the original on 5 January 2025. Retrieved 18 April 2024.
- ↑ "ziglang/zig". Codeberg. Retrieved 11 February 2020.
- 1 2 3 "The Zig Programming Language". Ziglang.org. Retrieved 11 February 2020.
- ↑ Anderson, Tim (24 April 2020). "Keen to go _ExtInt? LLVM Clang compiler adds support for custom width integers". www.theregister.co.uk. Retrieved 30 December 2024.
- ↑ "Documentation". Ziglang.org. Retrieved 24 April 2020.
- ↑ "Announcing the Zig Software Foundation". Ziglang.org. Retrieved 28 May 2021.
- ↑ "Pledging Another $400,000 to the Zig Software Foundation". Mitchell Hashimoto. 21 June 2026. Retrieved 7 July 2026.
- ↑ Elizabeth 2017.
- ↑ Yegulalp 2016.
- 1 2 3 4 5 "Allocators". 11 September 2023.
- ↑ Tyson, Matthew (9 March 2023). "Meet Zig: The modern alternative to C". InfoWorld.com.
- 1 2 "Zig 0.16.0 Release Notes". Zig Release Notes. 14 April 2026. Retrieved 24 April 2026.
{{cite web}}: CS1 maint: url-status (link) - ↑ The Road to Zig 1.0 - Andrew Kelley. ChariotSolutions. 9 May 2019 – via YouTube.
- ↑ "Zig Language Reference: Compile-Time Parameters".
- ↑ "0.6.0 Release Notes". Ziglang.org. Retrieved 19 April 2020.
- ↑ "'zig cc': a Powerful Drop-In Replacement for GCC/Clang - Andrew Kelley". andrewkelley.me. Retrieved 28 May 2021.
- ↑ "Zig Makes Go Cross Compilation Just Work". DEV Community. 24 January 2021. Retrieved 28 May 2021.
- ↑ "0.15.1 Release Notes ⚡ The Zig Programming Language". ziglang.org. Retrieved 3 September 2025.
- ↑ andrewrk. "daw". Codeberg.org. Retrieved 29 May 2026.
- ↑ Anderson, Tim (28 May 2026). "Zig creator seeks 'uncompromising perfection' before blessing 1.0". theregister. Retrieved 29 May 2026.
- ↑ andrewrk (13 March 2024). "origin of the zig programming language name. by @andrewrk". Retrieved 13 March 2024.
- ↑ "A Reply to _The Road to Zig 1.0_". www.gingerbill.org. 13 May 2019. Retrieved 11 February 2020.
- ↑ "ziglang/zig". Codeberg. Zig Programming Language. 11 February 2020. Retrieved 11 February 2020.
- ↑ "The Zig Programming Language". Ziglang.org. Retrieved 11 February 2020.
- 1 2 Kelley, Andrew (26 November 2025). "Migrating from GitHub to Codeberg". ziglang.org. Archived from the original on 27 November 2025. Retrieved 27 November 2025.
- 1 2 Claburn, Thomas (2 December 2025). "Zig quits GitHub, gripes about Microsoft's AI obsession". theregister. Retrieved 8 August 2026.
- ↑ Dees, Mels (2 December 2025). "Zig project leaves GitHub due to excessive AI". Techzine Global. Retrieved 8 August 2026.
- ↑ Claburn, Thomas (23 July 2026). "Codeberg gives vibe-coded projects the toss, promotes human FLOSS". theregister. Retrieved 8 August 2026.
- ↑ "Codeberg Has Drawn a Hard Line on Use of AI With Community Backing". It's FOSS. 24 July 2026. Retrieved 8 August 2026.
- ↑ Sumner, Jarred (8 July 2026). "Rewriting Bun in Rust". Bun Blog.
- ↑ Greef, Joran Dirk (4 August 2023). "A New Era for Database Design with TigerBeetle". InfoQ. Retrieved 28 January 2026.
- ↑ tigerbeetle/tigerbeetle, TigerBeetle, 28 January 2026, retrieved 28 January 2026
- ↑ Proven, Liam (8 January 2025). "Just when you thought terminal emulators couldn't get any better, Ghostty ships". The Register.
Bibliography
[edit]- Elizabeth, Jane (19 October 2017). "Tired of C? New programming language Zig aims to be more pragmatic and readable". jaxenter. Archived from the original on 1 October 2020. Retrieved 22 April 2020.
- Yegulalp, Serdar (29 August 2016). "New challenger joins Rust to topple C language". InfoWorld. Retrieved 11 February 2020.
External links
[edit]- C (programming language) compilers
- Compiled programming languages
- Cross-platform free software
- Cross-platform software
- Embedded systems
- Free and open source compilers
- Free computer libraries
- High-level programming languages
- Programming languages
- Programming languages created in 2015
- Software using the MIT license
- Statically typed programming languages
- Systems programming languages