A Lightweight, High-Performance Server Framework for Lua
Features • Quick Start • Examples • Documentation • Contributing
- 🚀 High Performance - Handles 200,000+ requests/second with single-threaded architecture
- 🧵 Coroutine-Based - Clean async/await style code without callback hell
- 🌐 Rich Protocols - Built-in support for TCP, UDP, HTTP, WebSocket, gRPC, TLS
- 💾 Database Ready - Native MySQL, Redis, and Etcd integrations
- 🔐 Security - Comprehensive crypto suite including JWT, AES, RSA, HMAC
- 📊 Observability - Prometheus metrics and structured logging out of the box
- 🔧 Developer Friendly - Hot reload, interactive debugger, and extensive APIs
# Clone the repository
git clone https://github.com/findstr/silly.git
cd silly
# Build (supports Linux, macOS, Windows)
# OpenSSL support is enabled by default for TLS
make
# Disable OpenSSL if not needed
make OPENSSL=offCreate a file hello.lua:
local tcp = require "silly.net.tcp"
local server = tcp.listen {
addr = "127.0.0.1:8888",
accept = function(conn)
print("New connection from", conn.remoteaddr)
while true do
local data, err = conn:read("\n")
if err then
print("Client disconnected")
break
end
conn:write("Echo: " .. data)
end
conn:close()
end
}
print("Server listening on 127.0.0.1:8888")Run the server:
./silly hello.luaTest with telnet or netcat:
echo "Hello Silly\!" | nc localhost 8888Benchmarked on Intel Core i7-10700 @ 2.90GHz using redis-benchmark:
| Test | Throughput (req/s) | Avg Latency | P99 Latency |
|---|---|---|---|
| PING_INLINE | 235,849 | 0.230ms | 0.367ms |
| PING_MBULK | 224,719 | 0.241ms | 0.479ms |
local silly = require "silly"
local http = require "silly.net.http"
local server = http.listen {
addr = "0.0.0.0:8080",
handler = function(stream)
local response_body = "Hello from Silly!"
stream:respond(200, {
["content-type"] = "text/plain",
["content-length"] = #response_body,
})
stream:closewrite(response_body)
end
}
print("HTTP server listening on http://0.0.0.0:8080")local silly = require "silly"
local http = require "silly.net.http"
local websocket = require "silly.net.websocket"
http.listen {
addr = "127.0.0.1:8080",
handler = function(stream)
if stream.header["upgrade"] ~= "websocket" then
stream:respond(404, {})
stream:close("Not Found")
return
end
local sock, err = websocket.upgrade(stream)
if not sock then
print("Upgrade failed:", err)
return
end
print("New client connected")
while true do
local data, typ = sock:read()
if not data or typ == "close" then
break
end
if typ == "text" then
sock:write("Echo: " .. data, "text")
end
end
sock:close()
end
}
print("WebSocket server listening on ws://0.0.0.0:8080")local mysql = require "silly.store.mysql"
local db = mysql.open {
addr = "127.0.0.1:3306",
user = "root",
password = "password",
database = "mydb",
charset = "utf8mb4",
max_open_conns = 10,
max_idle_conns = 5,
}
local users, err = db:query("SELECT * FROM users WHERE age > ?", 18)
if users then
for _, user in ipairs(users) do
print(user.name, user.email)
end
else
print("Query failed:", err.message)
end
db:close()For more examples, check out the tutorials in the documentation.
Comprehensive documentation is available at https://findstr.github.io/silly/
Silly uses a hybrid threading model for optimal performance:
┌─────────────────────────────────────────────────────┐
│ Silly Framework │
├──────────────┬──────────────┬──────────────┬────────┤
│ Worker Thread│ Socket Thread│ Timer Thread │Monitor │
│ (Lua VM) │ (epoll/kqueue│ (10ms res) │ Thread │
│ │ /iocp) │ │ │
│ • Coroutine │ • I/O Events │ • Timers │• Health│
│ • Business │ • 65K conns │ • Schedulers │ Check │
│ Logic │ │ │ │
└──────────────┴──────────────┴──────────────┴────────┘
Key design principles:
- Single-threaded business logic - No locks, no race conditions
- Asynchronous I/O - Event-driven socket operations
- Coroutine-based - Clean async code without callbacks
| Module | Description | Documentation |
|---|---|---|
silly.net |
TCP, UDP, HTTP, WebSocket, gRPC, TLS | API |
silly.store |
MySQL, Redis, Etcd | API |
silly.crypto |
AES, RSA, HMAC, Hash | API |
silly.sync |
Channel, Mutex, WaitGroup | API |
silly.security |
JWT authentication | API |
silly.metrics |
Prometheus metrics | API |
silly.logger |
Structured logging | API |
./silly main.lua [options]
Core Options:
-h, --help Display help message
-v, --version Show version
-d, --daemon Run as daemon
Logging:
-p, --logpath PATH Log file path
-l, --loglevel LEVEL Log level (debug/info/warn/error)
-f, --pidfile FILE PID file path
Custom Options:
--key=value Custom key-value pairsExample with custom options:
./silly server.lua --port=8080 --workers=4 --env=productionAccess in Lua:
local env = require "silly.env"
local port = env.get("port") -- "8080"
local workers = env.get("workers") -- "4"
local environment = env.get("env") -- "production"Run the complete test suite:
# Run all tests
make testall
# Run with address sanitizer (Linux/macOS)
make testSilly has minimal dependencies:
- Lua 5.4 (embedded)
- jemalloc (optional, for better memory allocation)
- OpenSSL (optional, for TLS support)
- zlib (embedded, for compression)
All dependencies are automatically built via Git submodules.
We welcome contributions! Please see CONTRIBUTING.md for details.
# Clone with submodules
git clone --recursive https://github.com/findstr/silly.git
# Build in debug mode
make test
# Format code
make fmtSilly is licensed under the MIT License.
- Lua - The elegant scripting language
- jemalloc - Scalable concurrent memory allocator
- OpenSSL - Robust cryptography toolkit
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Official Docs