A modern, secure, single-binary alternative to PHP
Dirge is a high-performance web engine that combines the simplicity of PHP with modern security and scalability. Write HTML with embedded scripts in .dx files, deploy a single binary, and scale from hobby projects to enterprise applications.
<!-- hello.dx -->
~{ name = "World" }
<h1>Hello, ~{ name }!</h1>
<p>Current time: ~{ GetTime("", TimeNow()) }</p>- Single Binary - No runtime dependencies, ~50MB
- Drop-in Templates -
.dxfiles with embedded~{ }scripts - Security First - Auto-escape HTML, sandboxed plugins, prepared statements
- Blazing Fast - ~14Β΅s per request, optimized for high concurrency
- Native Minification - HTML/CSS/JS minified in-memory, respects
~{ }scripts - Hot-Reload Plugins - Edit Lua plugins without restarting server
- Event-Driven - WordPress-style hooks and pub/sub events for plugins
- Enhanced Sandboxing - Resource limits, function restrictions
- Flexible Deployment - Monolithic, edge-enabled, or multi-region
- Zero Config - Works out-of-box, customize with TOML
50+ Built-in Functions
| Category | Functions |
|---|---|
| Time | GetTime(), GetDate(), GetYear(), GetMonth(), GetDay(), GetHour(), GetMinute(), GetSecond(), TimeNow(), TimeUnix(), TimeUnixNano(), Add(), Subtract(), Diff(), DiffAbs(), FormatUTC() |
| String | Len(), Contains(), Split(), Join(), Trim(), TrimSpace(), ToUpper(), ToLower(), Replace(), HasPrefix(), HasSuffix(), Index(), Substring() |
| Math | Abs(), Min(), Max(), Round(), Floor(), Ceil(), Pow(), Sqrt(), RandomInt(), RandomFloat() |
| Array | ArrLen(), ArrAppend(), ArrContains(), ArrIndex(), ArrReverse(), ArrSlice(), ArrFirst(), ArrLast(), SortStrings(), SortInts() |
| HTTP | HTTPGet(), HTTPPost(), HTTPRequest() |
| File I/O | ReadFile(), WriteFile(), FileExists() |
| Cache | CacheSet(), CacheGet(), CacheDelete(), CacheClear() |
| Database | DBGet(), DBList(), DBCreate(), DBUpdate(), DBDelete(), DBQuery(), DBExec() |
| Request | Query(), Param(), ParamInt(), ParamBool(), Body(), BodyJSON(), BodyRaw(), BodyFile() |
| Session | CreateSession(), GetCurrentUser(), IsAuthenticated(), GetSessionData(), SetSessionData() |
| Utility | If(), GetField(), GetIndex(), escape(), unescape(), Raw(), Sleep(), Env(), Print(), Println(), Sprintf(), TypeOf(), IsNil(), ToString(), ToInt(), ToFloat(), ToBool(), Json(), JsString() |
6 Database Drivers
- SQLite3 - Default, zero-config, perfect for development
- PostgreSQL - Full SQL support with connection pooling
- MySQL/MariaDB - Wide compatibility
- MongoDB - NoSQL document store support
- CockroachDB - Distributed SQL, geo-replicated
- YugabyteDB - PostgreSQL-compatible distributed database
Features: Connection pooling, query builder, prepared statements, ORM-like functionality, transactions, migrations (up/down/status/create), schema management, CSV/JSON import, full-text search
Authentication & Security
Auth Types:
- Session-based (cookie-based for traditional web apps)
- JWT (stateless APIs, mobile apps)
- PASETO v4 (modern alternative with v4.public/v4.local variants)
- OAuth2/OIDC (multiple providers with auto-registration)
- BasicAuth (admin panel protection)
Key Management:
- Automatic key rotation (symmetric and Ed25519)
- gRPC-based key distribution across nodes
- mTLS for node-to-node communication
- Clock skew tolerance
Security Features:
- RBAC registry with custom permission system
- CSRF protection (token-based)
- Content Security Policy headers
- XSS prevention (auto-HTML escaping)
- Path traversal protection (sandbox enforcement)
- SQL injection prevention (prepared statements only)
- Configurable CORS
Caching System
Backends:
- In-memory (fast, in-process)
- File cache (persistent, disk-based)
- Redis/Valkey (distributed, multi-node)
- Tiered cache (memory + file hybrid)
Features: TTL support, minification caching, function result caching, whitelist/blacklist paths, token caching, ModTime validation
Lua Plugin System
- Full Lua 5.1 support via GopherLua
- Hot-reload without server restart
- Sandboxing with resource limits
- Inter-plugin communication via events and hooks
- Plugin registry with lifecycle hooks
- Full access to database, HTTP client, and cache APIs
Real-time Communication
- WebSocket hub with broadcasting
- User channels and room-based routing
- Optional authentication requirement
- Message compression
- Configurable buffer sizes and max message size
- Presence tracking and typing indicators
Distributed Systems
- Consul integration for service discovery
- Redis/Valkey for distributed cache and sessions
- mTLS encrypted node-to-node communication
- Automatic failover to secondary nodes
- Mesh networking with node roles (standalone, master, auth, service, worker, health)
- Heartbeat protocol with configurable intervals
- LAN/WAN/satellite latency classes
Observability & Monitoring
- Structured JSON logging
- In-memory log buffer (1000 entries)
- SQL query logging with bind parameters
- Async error tracking
- Prometheus metrics export (
::Metrics:prometheus) - Health checks (
::Health:live,::Health:ready,::Health:startup) - OpenTelemetry distributed tracing (OTLP HTTP)
- Flight recorder (Go 1.25+)
- Security audit logging
Static Files & Media
- Static asset routing with automatic minification
- Dynamic media routing
- MIME type handling with cache headers (ETag, Cache-Control)
- Gzip/Brotli compression middleware
- Image Processing: libvips integration for resizing, conversion, quality control, metadata stripping
- File Uploads: Multipart support, configurable storage, filename hashing, date organization, MIME filtering
Cloudflare Integration
- Real IP detection (CF-Connecting-IP)
- Country detection (CF-IPCountry)
- Ray tracing (CF-Ray)
- Edge caching (s-maxage)
- Cache tags and purging via API
- Early hints (103 responses)
- Auto-updating Cloudflare IP ranges
Additional Features
- Analytics: Request tracking, performance metrics, referrer/user-agent tracking, device classification, multiple backends (memory/Redis/SQLite)
- Notifications: Multi-channel delivery (WebSocket, email, webhooks), per-user limits, TTL support
- Scheduler: Cron-like task scheduling, rate limiting, persistent storage
- Rate Limiting: IP-based throttling, configurable limits, distributed support via Redis
- Circuit Breaker: Failure detection, state management, fallback support
- Moderation: Content filtering, user banning, report system, audit trail
CLI Commands
dirge init <name> # Create new project scaffold
dirge run # Start dev server with live reload
dirge build [--compress] # Build optimized binary (with UPX option)
dirge migrate up # Apply pending migrations
dirge migrate down [steps] # Rollback migrations
dirge migrate status # Show migration status
dirge migrate create <name> # Create new migration
dirge version # Show version info
dirge help # Show help messageConfig flag: -c or --config for custom config file
I got tired of rebuilding, refactoring routes, and recompiling on every change. So I built on Fiber v3 for speed and simplicity.
# Download latest release
wget https://github.com/requiem-eco/dirge/releases/latest/download/dirge-linux-amd64
# Make executable
chmod +x dirge-linux-amd64
mv dirge-linux-amd64 dirge
# Run
./dirge# Clone repository
git clone https://github.com/requiem-eco/dirge.git
cd dirge
# Build standard binary
make build
# Build edge-optimized binary (smaller, cache-focused)
make edge
# Build for all regions
make edge-all
# Run
./dirgeDirge follows semantic versioning (MAJOR.MINOR.PATCH) with an optimized build strategy:
-
Automated builds on:
- Every major version (X.0.0)
- Every 15 minor versions (0.15.0, 0.30.0, etc.)
- Critical patches (tagged with
[critical])
-
Manual builds available for all other versions via source
Latest Release: Check GitHub Releases for binaries
- Create a
.dxfile in thehome/directory:
<!-- home/hello.dx -->
<!DOCTYPE html>
<html>
<head><title>My First Dirge Page</title></head>
<body>
~{ name = "Dirge" }
<h1>Welcome to ~{ name }!</h1>
<p>Random number: ~{ RandomInt(1, 100) }</p>
</body>
</html>- Start the server:
./dirge- Visit
http://localhost:8080/hello
Synchronous ~{ } - Executes and waits for result (default)
Asynchronous ~!{ } - Executes in background, doesn't block render
~{ x = 42 }
~{ name = "Alice" }
<p>x = ~{ x }, x * 2 = ~{ x * 2 }</p>
<p>Hello ~{ ToUpper(name) }!</p><!-- String operations -->
<p>Length: ~{ Len("Hello") }</p>
<p>Upper: ~{ ToUpper("hello") }</p>
<!-- Math operations -->
<p>Random: ~{ RandomInt(1, 100) }</p>
<p>Power: ~{ Pow(2, 10) }</p>
<!-- Time operations -->
<p>Now: ~{ GetTime("", TimeNow()) }</p>
<p>Unix: ~{ TimeUnix() }</p><!-- routes.toml: path = "/user/:id" -->
<h1>User ID: ~{ Param("id") }</h1>
<p>Age: ~{ ParamInt("age") }</p>
<p>Query: ~{ Query("search") }</p>Execute long-running tasks in background without blocking page render:
<!-- Execute in background with ~!{ } -->
~!{ Sleep(10) }
~!{ CacheSet("background_task", HTTPGet("https://api.example.com/data"), 60) }
<p>Page rendered immediately! Tasks running in background.</p>Use cases for ~!{ }:
- API calls that take >1s
- Cache warming
- Background data processing
- Stateful caching operations
Dirge supports multiple databases including geo-distributed options:
- SQLite3 - Default, zero-config, perfect for development
- PostgreSQL - Production-ready, full-featured
- MySQL/MariaDB - Wide compatibility
- MongoDB - NoSQL document store
- CockroachDB - Geo-distributed SQL, automatic failover
- YugabyteDB - PostgreSQL-compatible, tunable consistency
[database]
type = "cockroachdb"
dsn = "postgresql://dirge@lb:26257/dirge?sslmode=require"
[database.multi_region]
enabled = true
home_region = "us-east-1"
follower_reads = true # Low-latency reads from local replicasCreate config.toml:
[server]
bind = "0.0.0.0"
port = 8080
root = "./home"
sandbox = true
[http]
tls_enabled = false
allow_cors = true
cors_origins = ["*"]
[limits]
max_request_size = 1048576 # 1MB
max_concurrent_scripts = 100
[cache]
allow_caching = true
cache_memory = true
cache_ttl = 60Hot-Reload: Edit plugins without restarting server (when live-reload enabled)
Events & Hooks: WordPress-style filters/actions and pub/sub events
Sandboxed: Resource limits, restricted functions, secure by default
-- internals/plugins/api.lua
plugin.register("getUserData", function(ctx)
local userId = ctx:paramInt("id")
return ctx:jsonSuccess({
user = {id = userId, name = "John Doe"}
})
end, {
public = true,
methods = {"GET"}
})-- Plugin A: Emit events
plugin.register("createUser", function(ctx)
-- ... create user ...
plugin.emit("user.register", {user_id = 123})
return ctx:jsonSuccess({id = 123})
end, {public = true, methods = {"POST"}})
-- Plugin B: Listen to events
plugin.on("user.register", function(event)
print("New user:", event.data.user_id)
-- Send welcome email, update analytics, etc.
end)
-- Plugin C: Modify data with filters
plugin.addFilter("user.display_name", 10, function(name, userId)
if userId == 1 then
return name .. " [Admin]"
end
return name
end)Map to routes in routes.toml:
[[routes]]
path = "/api/user/:id"
handler = "::getUserData"Serve static files with automatic minification:
# routes.toml
[[media]] # doesn't minify
types = "png,jpg,jpeg,gif"
base_url = "/media"
base_dir = "./media"
dynamic = true
[[assets]]
types = "css,js"
base_url = "/assets"
base_dir = "./assets"
dynamic = false # Pre-map files on startupAssets are automatically minified and cached in memory.
Dirge runs two separate HTTP servers:
- Main Server (port 8080): Public-facing, serves
[[routes]] - Command Server (port 8081): Admin-only, serves
[[admin]]routes
Admin routes are isolated from public traffic for security:
# routes.toml
[[admin]]
path = "/metrics"
handler = "/admin-home/metrics.dx"
[[admin]]
path = "/reload"
handler = "::reloadCache"Security:
- Admin routes only accessible on port 8081
- Bind command server to
127.0.0.1for localhost-only access - Use firewall rules to block external access
- Add BasicAuth middleware for additional protection
Configuration:
[server]
bind = "0.0.0.0" # Main server - public
port = 8080
cmd_bind = "127.0.0.1" # Command server - localhost only
cmd_port = 8081
[auth]
enabled = true
type = "standard" # Options: "standard", "jwt", "paseto"Dirge provides flexible authentication primitives instead of rigid RBAC:
Three Auth Modes:
- Standard: Cookie-based sessions (traditional web apps)
- PASETO v4: Modern alternative to JWT (better security)
- v4.public (Ed25519 signing) - Main server only, verifiable by anyone
- v4.local (symmetric encryption) - Admin server & inter-node communication
Extensibility via Lua Plugins: Build any auth system you need - from simple login to complex RBAC, multi-tenancy, or custom permissions.
-- Example: Custom permission system in Lua
function deleteUser()
if not hasPermission("users.delete") then
return {error = "Forbidden"}
end
-- Delete user logic
end
register("deleteUser", {public = true, methods = {"DELETE"}})Available Functions:
getCurrentUser()- Get authenticated userhasPermission(perm)- Check custom permissionhasRole(role)- Check custom rolegetSessionData(key)- Retrieve session data- Plugin hooks:
onLogin,onLogout,onRequest
Current Benchmarks (Last tested: 2025-11-24 on AMD Ryzen 7 2700X)
Disclaimer: Tests were performed on AMD Ryzen 7 2700X with a Western Digital Ultrastar DC SN200 NVMe SSD (3,350 MB/s seq read, 835K IOPS random read) in a minimal/base environment. Large-scale production systems with higher loads, multiple services, or resource contention may experience different performance characteristics.
| Metric | Result |
|---|---|
| Throughput | 66,059 req/sec (2000 concurrent goroutines) |
| Average Response Time | 30.275 ms |
| 99th Percentile | 1.204 ms |
| Fastest Request | 141 Β΅s |
| Slowest Request | 552.543 ms |
| Template Rendering | 13.2 Β΅s/req (151x faster than 2ms target) |
| Route Matching | 994 ns/match (2011x faster than 2ms target) |
| Script Parsing | 2.06 Β΅s/parse (972x faster than 2ms target) |
| Cache Speedup | 2.6x faster than disk reads |
| Binary Size | ~50 MB |
| Memory per Request | ~3.2 KB |
| Error Rate | 0% (1,981,567 requests) |
Test Suite Status:
- 87 tests passed, 5 skipped, 0 failed
- 100% security tests passing (XSS, SQL injection, path traversal prevention)
- All core modules validated
Optimizations:
- In-memory HTML/CSS/JS minification
- File cache with ModTime validation (2.6x faster than disk)
- Zero-copy static file serving
- Connection pooling (DB, HTTP)
- Worker pool (100 goroutines)
- Minimal allocations per request
Run cd tests/benchmark && go test -bench=. -benchmem to benchmark on your hardware
Deployment Modes:
- Monolithic: Single instance, local cache/DB (current)
- Edge-Enabled: Main mesh + lightweight edge gateways (planned)
- Distributed: Full multi-region with geo-distributed database (future)
Dirge has a comprehensive test suite covering all modules:
# Run all tests
cd tests && go run main.go --build
# Run specific module
go run main.go server
go run main.go database
go run main.go plugins
# With coverage
go run main.go --coverage
# Performance benchmarks
cd benchmark && go test -bench=. -benchmemTest Coverage:
- β Server (routing, middleware, handlers)
- β Router (path matching, parameters)
- β Database (query builder, ORM, security)
- β Plugins (lifecycle, events, hooks, sandbox)
- β Script engine (parser, renderer, functions, XSS prevention)
- β Cache system (memory, file, minification, expiration)
- β Auth system (sessions, security, concurrency)
- β Security (XSS, SQL injection, path traversal prevention)
- β Integration (end-to-end scenarios, concurrent requests)
CI/CD Ready:
- Automated testing on PR/push
- Performance regression detection
- Security scanning
- Cross-platform builds
Completed:
- Core
.dxexecution engine - Built-in functions (50+ functions)
- HTTP client for API requests
- Scheduler system (cron-like)
- Lua plugin system with hot-reload
- Inter-plugin communication (events & hooks)
- Enhanced sandboxing (resource limits)
- Native HTML/CSS/JS minifier
- Media & asset routing
- Database ORM with query builder
- Database migrations system (up/down/status/create)
- Live reload (file watching)
- Authentication primitives (sessions, JWT, PASETO)
- Admin panel (command server)
- Comprehensive test suite
- CLI tooling (init, run, build, migrate)
- Auto-update mechanism with GitHub releases
- Edge binary builds (lightweight gateways)
In Progress:
- Multi-region support with CockroachDB/YugabyteDB
Planned:
- Consul service mesh integration
- Request coalescing & stale-while-revalidate
- Cross-region write strategies
- mTLS for edge-to-mesh communication
- Geo-partitioned data support
- WebSocket relay for edge nodes
- Metrics & observability (Prometheus)
- Plugin marketplace
Dirge Source-Available License 1.0.0
Copyright (c) 2025 SevensRequiem
This software is source-available but NOT open-source. Key restrictions:
- β View, fork, and modify for personal/educational use
- β Contribute to official repository
- β Commercial use without license
- β Redistribution of binaries
- β Hosting forks outside official organization
Commercial Licenses: Available for businesses and resellers. Contact: licensing@dirge.one
Future: Automatically converts to MIT License on January 1, 2035 unless updated.
See LICENSE for full terms.
- XAMPP-like simplicity
- Single binary deployment
- No complex setup
- Rapid prototyping
- Built-in admin panel
- Easy scaling path
- High concurrency
- Horizontal scaling
- Internal tools
Contributions are welcome! Please follow these steps:
- Fork within the official organization
- Follow existing code style (
gofmt) - Add tests for new features (mandatory)
- Run test suite before PR:
cd tests && go run main.go --build - Update documentation
- Ensure all tests pass (no exceptions)
- Documentation: docs.dirge.one (Coming Soon)
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Commercial: licensing@dirge.one
Built with:
Made with β€οΈ by SevensRequiem
why "dirge"? i was thinking of "requiem" related words and remembered this song: Dirge
or maybe it references Naomi Misora..
Can it run on a Floppy Disk?
isTar = true in cnf for grey mode