Zigar is a web application framework for Zig that supports ASP / JSP-like template syntax with ASP-style tags (<% %> and <%= %>).
- ASP-style Template Tags: Use
<% ... %>for code blocks and<%= ... %>for expressions - Template Transpilation: HTML templates are transpiled to native Zig code
- Static File Serving: Files in
/staticfolder are served without transpilation - Dev Mode: Rapid development with template transpilation
- Production Mode: Compile everything into a single binary
- URL Mapping:
template.htmlautomatically maps to/template.htmlroute
-
Install Zig (version 0.13.0 or later):
# macOS brew install zig` # Linux # Download from https://ziglang.org/download/ # Or use a version manager
-
Clone or download this project
zigar/
├── build.zig # Build configuration
├── src/
│ ├── main.zig # Main application entry point
│ ├── server.zig # HTTP server implementation
│ └── transpiler.zig # Template transpiler
├── templates/ # HTML templates with Zig code
│ ├── index.html
│ ├── about.html
│ └── demo.html
├── static/ # Static files (CSS, JS, images)
│ ├── style.css
│ └── logo.svg
└── generated/ # Transpiled Zig files (auto-generated)
First, transpile templates:
zig run build_templates.zigThen run the server in development mode:
zig build run -- --devOr with a custom port:
zig build run -- --dev --port=3000Or use the convenient start script:
./start.shIn dev mode:
- Templates must be transpiled before building
- Changes require re-transpiling and server restart
- Access at http://localhost:8080
Transpile templates and build a production binary:
zig run build_templates.zig
zig build -Doptimize=ReleaseFast
./zig-out/bin/zigar --prodInclude other template files (like PHP include):
<%@ include file="includes/header.html" %>
<%@ include "includes/nav.html" %>
<%@ import file="includes/footer.html" %>Features:
- Recursive includes (up to 10 levels)
- Variables from parent template are accessible
- Paths relative to templates directory
- See INCLUDES.md for detailed documentation
Execute Zig code without output:
<% const name = "World"; %>
<% var count: u32 = 0; %>
<% while (count < 5) : (count += 1) { %>
<p>Line <%= count %></p>
<% } %>Output Zig expressions:
<p>Current timestamp: <%= std.time.timestamp() %></p>
<p>Random number: <%= std.crypto.random.int(u32) %></p>
<p>Calculation: <%= 2 + 2 * 3 %></p><% const hour = @rem(@as(i64, @intCast(std.time.timestamp())) / 3600, 24); %>
<% if (hour < 12) { %>
<p>Good morning!</p>
<% } else { %>
<p>Good afternoon!</p>
<% } %><ul>
<% var i: u32 = 1; while (i <= 5) : (i += 1) { %>
<li>Item <%= i %></li>
<% } %>
</ul>
<% const items = [_][]const u8{"Apple", "Banana", "Cherry"}; %>
<% for (items) |item| { %>
<p><%= item %></p>
<% } %>-
Template Transpilation: HTML files in
templates/are parsed and converted to Zig code- HTML content is converted to output statements
<% ... %>blocks become Zig code<%= ... %>expressions are formatted and appended to output
-
Route Generation: A
routes.zigfile is auto-generated that imports all transpiled templates -
HTTP Server: Routes requests to appropriate handlers or serves static files
-
URL Mapping:
/index.html→templates/index.html/about.html→templates/about.html/static/style.css→static/style.css(no transpilation)
templates/hello.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello, <%= "Zigar" %>!</h1>
<% const numbers = [_]u32{1, 2, 3, 4, 5}; %>
<ul>
<% for (numbers) |num| { %>
<li>Number: <%= num %>, Squared: <%= num * num %></li>
<% } %>
</ul>
</body>
</html>Access at: http://localhost:8080/hello.html
Place static assets in the static/ folder:
static/
├── style.css
├── script.js
├── logo.svg
└── images/
└── banner.png
Access with /static/ prefix:
-
Transpile and build:
zig build -Doptimize=ReleaseFast
-
The resulting binary includes all templates and can be deployed standalone:
./zig-out/bin/zigar --prod --port=8080
-
Copy the
static/folder alongside your binary if you have static assets
Each transpiled template generates a handler function:
pub fn handler(allocator: std.mem.Allocator, req: *std.http.Server.Request) ![]u8 {
// Your template code here
// Returns HTML as []u8
}The req parameter provides access to request information:
<p>Method: <%= @tagName(req.head.method) %></p>
<p>Path: <%= req.head.target %></p>- Template changes require server restart (no hot reload yet)
- Each template must be a complete, valid Zig code when transpiled
- Error messages may reference generated code rather than template files
- Hot reload in dev mode
- Template includes/imports
- Request parameter parsing
- Session management
- Template compilation caching
- Better error messages with template line numbers
- Middleware support
- Database integration examples
MIT License - feel free to use this in your projects!
This is a demonstration project. Feel free to fork and extend it for your needs!