This is a demo project showing how to build a complete web application using the Spider Web Framework in Zig, with several modern technologies integrated.
Official Website: https://www.spiderme.org/
- Language: Zig 0.16.0-dev.2984+cb7d2b056
- Web Framework: Spider - full-featured web framework for Zig
- Database: PostgreSQL 16 (via Spider's native driver)
- Authentication: JWT + OAuth2 (Google Login)
- CSS: Tailwind CSS + DaisyUI
- Template: HTML server-side rendering
- Build: PostCSS + Autoprefixer
- Container: Docker + Docker Compose
- Zig Package Manager: Built-in (build.zig)
- Unified login/register interface
- Login via OAuth2 with Google
- Email/password authentication
- JWT token generation and validation
- Secure cookies for session
- User locale support
- Role-Based Access Control (RBAC)
- List games from database
- Create new game
- Update existing game
- Delete game
- Modal-based game editing
- Alpine.js for reactive UI components
- List, create, update, delete tasks
- HTMX for seamless updates without page reload
- Toggle completed status
- Dark theme UI
- Web manifest for installable app
- Service worker for offline capability
- Apple mobile web app support
- Theme color and icons
- Slide-in drawer navigation on mobile
- Alpine.js for reactive UI
- Smooth transitions
- Loading placeholders during navigation
- Server-side rendering com embedded templates
- Componentização com partials (topbar, sidebar, bottom_nav, drawer)
- Layout inheritance
- Support for Portuguese (pt-BR) and English (en-US)
- Locale based on Accept-Language header
- Date and number formatting
- JWT authentication
- Public vs private routes
- Automated migration system
- Schema version control
spiderstack/
├── build.zig # Zig build configuration
├── docker-compose.yml # PostgreSQL container
├── package.json # Dependencies (Tailwind, DaisyUI)
├── tailwind.config.js # Tailwind configuration
├── postcss.config.js # PostCSS configuration
├── .env # Environment variables
│
├── src/
│ ├── main.zig # Entry point - routes and configuration
│ ├── root.zig # Root module
│ ├── embedded_templates.zig # Generated embedded templates
│ │
│ ├── core/ # Core functionality
│ │ ├── config/ # Configuration
│ │ ├── context/ # Request context
│ │ ├── db/ # Database + migrations
│ │ ├── errors/ # Error handling
│ │ ├── i18n/ # Internationalization
│ │ ├── middleware/ # Auth middleware
│ │ └── utils/ # Utilities
│ │
│ ├── features/ # Application features
│ │ ├── auth/ # Authentication (Google OAuth)
│ │ ├── games/ # Games CRUD
│ │ ├── home/ # Home page
│ │ └── todo/ # Todo list CRUD
│ │
│ └── shared/ # Shared templates
│ └── templates/ # HTML layout, partials
│ └── partials/ # topbar, sidebar, bottom_nav, drawer
│
└── public/
├── css/ # Compiled CSS output
├── icons/ # PWA icons (192, 512)
├── manifest.json # PWA manifest
└── sw.js # Service Worker
docker-compose up -dnpm run build:css
# or watch mode
npm run watch:csszig build runThe application will be available at http://127.0.0.1:8080
PostgreSQL Client Library (libpq) is required to compile this project.
pacman -S postgresql-libssudo apt install libpq-devsudo dnf install postgresql-develbrew install libpqpkg-config --exists libpq && echo "ok"# Unit tests (no database required)
zig build test
# Integration tests (requires database)
zig build test-integration| Method | Path | Description | Auth |
|---|---|---|---|
| GET | / |
Home page | ✅ |
| GET | /login |
Login page | ❌ |
| GET | /auth/google |
Redirect to Google | ❌ |
| GET | /auth/google/callback |
OAuth callback | ❌ |
| POST | /auth/email/register |
Email registration | ❌ |
| POST | /auth/email/login |
Email login | ❌ |
| GET | /logout |
Logout user | ✅ |
| GET | /todo |
Todo list | ✅ |
| POST | /todo/create |
Create todo | ✅ |
| POST | /todo/:id/update |
Update todo | ✅ |
| POST | /todo/:id/delete |
Delete todo | ✅ |
| GET | /games |
Game list | ✅ |
| POST | /games/create |
Create game | ✅ |
| POST | /games/:id/update |
Update game | ✅ |
| POST | /games/:id/delete |
Delete game | ✅ |
# Database
POSTGRES_HOST=localhost
POSTGRES_PORT=5434
POSTGRES_USER=spider
POSTGRES_PASSWORD=spider
POSTGRES_DB=spiderdb
# Google OAuth
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
GOOGLE_REDIRECT_URI=http://localhost:8080/auth/google/callback
# JWT
JWT_SECRET=your_secret_keyid SERIAL PRIMARY KEY
email VARCHAR(255) UNIQUE NOT NULL
name VARCHAR(255)
locale VARCHAR(10) DEFAULT 'pt-BR'
locale_set BOOLEAN DEFAULT FALSE
created_at TIMESTAMPTZ DEFAULT NOW()id SERIAL PRIMARY KEY
name VARCHAR(255) NOT NULL
platform VARCHAR(100)
release_year INTEGER
genre VARCHAR(100)
developer VARCHAR(255)
sales_millions DECIMAL(10,2)
rating DECIMAL(3,1)
created_at TIMESTAMPTZ DEFAULT NOW()id SERIAL PRIMARY KEY
title VARCHAR(255) NOT NULL
completed BOOLEAN DEFAULT FALSE
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()const templates = @import("embedded_templates.zig").EmbeddedTemplates;
var server = try spider.Spider.init(arena, io, "127.0.0.1", 8080, .{
.templates = templates,
});Templates are embedded at compile time via generateEmbeddedTemplates in build.zig:
gen.addArg("src/embedded_templates.zig");server
.get("/", home.controller.index)
.post("/games/create", games.controller.create)
.use(middleware.auth) // applies to all following routes// Redirect
return Response.redirect(alloc, "/path");
// Render view with chuckBerry (embedded templates)
return spider.chuckBerry(alloc, req, "home/index", context);
// Text response
return Response.text(alloc, "message");// Simple query
const result = try db.query(MyStruct, alloc, "SELECT * FROM table", .{});
// Insert/Update with RETURNING
const new_row = try db.queryOne(MyStruct, alloc, "INSERT INTO ... RETURNING ...", .{});
// Transaction
var tx = try db.begin();
defer tx.rollback();
// ... operations
try tx.commit();zig build -Drelease-safe
# or
zig build -Drelease-fastThe compiled binary will be at zig-out/bin/spiderstack
- Author: Seven
- Email: 7b37b3@gmail.com
- Twitter: @1111O11OO11
- ARCHITECTURE.md - Detailed architecture patterns and conventions