Simple. Fast. Efficient.

Nyx is a self-hosting compiled language — the compiler is written in Nyx itself. The HTTP server and reverse proxy hosting this website are also built and compiled in Nyx.

Get Started GitHub

Simple

Clean syntax. No hidden complexity. A language you can learn in a weekend.

Fast

Compiles to native code via LLVM. Fibonacci runs in 0.87x of C.

Efficient

Three production binaries totaling 433KB. Zero dependencies.

Everything you see runs on Nyx

Internet nyx-proxy (:443) nyx-serve (:3000)
nyx-kv (:6380)

Three binaries. 433KB total. Zero external dependencies. No Nginx. No Node.js. No Redis.

Built with Nyx

Real software running in production. Source code included.

nyx-kv Redis-compatible key-value store
82K ops/s 255K pipelined 132KB
// main.nx — nyx-kv entry point
// Redis-compatible key-value store built in Nyx
//
// Usage: nyx products/kv/main.nx
// Connect: redis-cli -p 6380
// Benchmark: redis-benchmark -h localhost -p 6380 -t set,get -n 100000 -q

import "products/kv/resp"
import "products/kv/store"
import "products/kv/commands"

// Global channel for dispatching client fds to workers
var g_ch: Map = Map.new()

// Worker: receive client fd from channel, serve commands in a loop
fn kv_worker() -> int {
    while 1 > 0 {
        let client: int = channel_recv(g_ch)
        if client < 0 { return 0 }

        g_connections = g_connections + 1

        // Command loop: read RESP commands until client disconnects
        var connected: bool = true
        while connected {
            let cmd: Array = resp_read_command_fast(client)
            if cmd.length() == 0 {
                connected = false
            } else {
                let response: String = dispatch_command(cmd, client)
                // "" means response was already written directly
                if response.length() > 0 {
                    tcp_write(client, response)
                }
            }
        }
        tcp_close(client)
    }
    return 0
}

fn main() {
    let port: int = 6380
    let num_workers: int = 128

    print("nyx-kv v0.1.0 — Redis-compatible KV store")
    print("Listening on port " + int_to_string(port))

    g_ch = channel_new(512)
    let server: int = tcp_listen("0.0.0.0", port)
    if server < 0 {
        print("ERROR: cannot listen on port " + int_to_string(port))
        return 0
    }

    // Spawn worker threads
    var i: int = 0
    while i < num_workers {
        thread_spawn(kv_worker)
        i = i + 1
    }
    print(int_to_string(num_workers) + " workers spawned, ready for connections...")

    // Accept loop: dispatch client fds via channel
    while 1 > 0 {
        let client: int = tcp_accept(server)
        if client >= 0 {
            channel_send(g_ch, client)
        }
    }
    return 0
}
nyx-serve HTTP framework for APIs and websites
9,971 req/s 150KB
// main.nx — nyx-serve example: serves the nyxlang.com landing page
//
// Usage: compile and run:
//   cp products/serve/main.nx script.nx
//   NYX_SKIP_SEMANTIC=1 ./nyx_bootstrap
//   clang -O2 script.ll runtime/*.c -lgc -lpthread -ldl -lm -lssl -lcrypto -lz -o /tmp/nyx_serve
//   /tmp/nyx_serve
//
// Then visit http://localhost:3000

import "std/web"
import "std/http"
import "products/serve/server"
import "products/serve/files"

fn handle_index(req: Request) -> Response {
    let html: String = read_file("website/static/index.html")
    return response_html(200, html)
}

fn handle_index_es(req: Request) -> Response {
    let html: String = read_file("website/static/es/index.html")
    return response_html(200, html)
}

fn handle_css(req: Request) -> Response {
    let css: String = read_file("website/static/style.css")
    let hdrs: Array = ["Content-Type", "text/css; charset=utf-8"]
    return Response { status: 200, headers_flat: hdrs, body: css }
}

fn handle_health(req: Request) -> Response {
    return response_json(200, "{\"status\": \"ok\"}")
}

fn main() {
    let app: App = app_new()

    // Routes
    app_get(app, "/", handle_index)
    app_get(app, "/es/", handle_index_es)
    app_get(app, "/style.css", handle_css)
    app_get(app, "/api/health", handle_health)

    // Static files fallback (serves CSS, JS, images from website/static/)
    serve_static(app, "website/static")

    // Start server: port 3000, 64 workers
    serve_app(app, 3000, 64)
    return 0
}
nyx-proxy HTTPS reverse proxy with TLS 1.3
4,282 req/s 151KB Connection pooling
// main.nx — nyx-proxy entry point
// Multi-threaded reverse proxy with optional TLS (HTTPS) support
//
// Usage: compile and run:
//   cp products/proxy/main.nx script.nx
//   NYX_SKIP_SEMANTIC=1 ./nyx_bootstrap
//   clang -O2 script.ll runtime/*.c -lgc -lpthread -ldl -lm -lssl -lcrypto -lz -o /tmp/nyx_proxy
//   /tmp/nyx_proxy
//
// Configure upstreams and TLS in products/proxy/proxy.toml

import "std/http"
import "std/proxy"
import "products/proxy/config"
import "products/proxy/router"

// Channel for dispatching accepted client fds to TLS workers
var g_proxy_ch: Map = Map.new()

// TLS worker: accept TLS handshake, serve keep-alive requests over TLS
fn tls_worker() -> int {
    while 1 > 0 {
        let client_fd: int = channel_recv(g_proxy_ch)
        if client_fd < 0 { return 0 }

        // TLS handshake (once per connection)
        let ssl_handle: int = tls_accept(client_fd)
        if ssl_handle == 0 {
            tcp_close(client_fd)
        } else {
            // Keep-alive loop: serve multiple requests per TLS connection
            var keep_alive: bool = true
            while keep_alive {
                let request_line: String = tls_read_line(ssl_handle)
                if request_line.length() == 0 {
                    keep_alive = false
                } else {
                    // Parse request line: "GET /path HTTP/1.1"
                    let parts: Array = request_line.split(" ")
                    var method: String = "GET"
                    var path: String = "/"
                    if parts.length() >= 2 {
                        method = parts[0]
                        path = parts[1]
                    }

                    // Parse headers
                    let headers: Array = []
                    var done: int = 0
                    while done == 0 {
                        let hline: String = tls_read_line(ssl_handle)
                        if hline.length() == 0 {
                            done = 1
                        } else {
                            let colon_idx: int = hline.indexOf(": ")
                            if colon_idx >= 0 {
                                let key: String = hline.substring(0, colon_idx)
                                let val: String = hline.substring(colon_idx + 2, hline.length())
                                headers.push(key)
                                headers.push(val)
                            }
                        }
                    }

                    // Read body if Content-Length present
                    var body: String = ""
                    let cl_str: String = http_find_header(headers, "Content-Length")
                    if cl_str.length() > 0 {
                        let cl: int = string_to_int(cl_str)
                        if cl > 0 {
                            body = tls_read(ssl_handle, cl)
                        }
                    }

                    // Route and respond
                    let request: Array = ["request", method, path, headers, body]
                    let response: String = proxy_dispatch(request)
                    if response.length() > 0 {
                        tls_write_conn(ssl_handle, response)
                    }

                    // Check Connection: close
                    let conn: String = http_find_header(headers, "Connection")
                    if conn == "close" {
                        keep_alive = false
                    }
                }
            }
            tls_close_conn(ssl_handle)
        }
    }
    return 0
}

// HTTP worker: keep-alive loop over plain TCP
fn http_worker() -> int {
    while 1 > 0 {
        let client: int = channel_recv(g_proxy_ch)
        if client < 0 { return 0 }

        var keep_alive: bool = true
        while keep_alive {
            let request: Array = http_parse_request_fast(client)
            let method: String = request[1]
            if method.length() == 0 {
                keep_alive = false
            } else {
                let response: String = proxy_dispatch(request)
                if response.length() > 0 {
                    tcp_write(client, response)
                }
                let headers: Array = request[3]
                let conn: String = http_find_header(headers, "Connection")
                if conn == "close" {
                    keep_alive = false
                }
            }
        }
        tcp_close(client)
    }
    return 0
}

fn print_upstreams() {
    var i: int = 0
    while i < g_upstream_count {
        let name: String = g_upstream_names[i]
        let prefix: String = g_upstream_prefixes[i]
        if prefix.length() > 0 {
            print("  " + name + " [" + prefix + "]")
        } else {
            print("  " + name + " [default]")
        }
        i = i + 1
    }
}

fn main() {
    load_config("products/proxy/proxy.toml")

    if g_tls_enabled == 1 {
        // HTTPS mode
        let tls_ok: int = tls_server_init(g_tls_cert, g_tls_key)
        if tls_ok < 0 {
            print("ERROR: TLS init failed — check cert/key paths")
            return 0
        }

        print("nyx-proxy v0.2.0 (HTTPS)")
        print("Listening on port " + int_to_string(g_listen_port) + " with " + int_to_string(g_workers) + " workers")
        print_upstreams()

        g_proxy_ch = channel_new(512)
        let server: int = tcp_listen("0.0.0.0", g_listen_port)
        if server < 0 {
            print("ERROR: cannot listen on port " + int_to_string(g_listen_port))
            return 0
        }

        // Spawn TLS workers
        var i: int = 0
        while i < g_workers {
            thread_spawn(tls_worker)
            i = i + 1
        }

        // Accept loop
        while 1 > 0 {
            let client: int = tcp_accept(server)
            if client >= 0 {
                channel_send(g_proxy_ch, client)
            }
        }
    } else {
        // HTTP mode with keep-alive
        print("nyx-proxy v0.2.0 (HTTP)")
        print("Listening on port " + int_to_string(g_listen_port) + " with " + int_to_string(g_workers) + " workers")
        print_upstreams()

        g_proxy_ch = channel_new(512)
        let server: int = tcp_listen("0.0.0.0", g_listen_port)
        if server < 0 {
            print("ERROR: cannot listen on port " + int_to_string(g_listen_port))
            return 0
        }

        var j: int = 0
        while j < g_workers {
            thread_spawn(http_worker)
            j = j + 1
        }

        while 1 > 0 {
            let client: int = tcp_accept(server)
            if client >= 0 {
                channel_send(g_proxy_ch, client)
            }
        }
    }
    return 0
}

All products are free and open source (Apache 2.0). This is the actual code running this website.

Numbers

0.87x
Fibonacci
vs C -O2
9,971
HTTP
req/s
82,713
KV GET
ops/s
255,102
KV pipelined
ops/s
433KB
total
binaries
224
tests
passing

Get started

Install
$ curl -sSf https://nyxlang.com/install.sh | sh
Hello World
fn main() {
    print("Hello, World!")
}
HTTP Server
import "std/http"

fn my_handler(request: Array) -> String {
    return http_response(200, "Hello!")
}

fn main() {
    http_serve_mt(8080, 64, my_handler)
}
Read the Book Playground

How Nyx was built

Nyx started as Helix, a compiler written in Racket. Once the language was mature enough, the compiler was rewritten in itself. The Racket dependency was removed entirely.

Today the Nyx compiler is written in Nyx, compiles to LLVM IR, and produces native binaries. Self-hosting is verified through a fixed point: compiling twice produces identical output.

The name comes from the Greek goddess of the night. Nyx is created by Ottavio Cavallina, with development assisted by AI tools.

compiler/*.nx → nyx_bootstrap → compiler/*.ll → clang → nyx_bootstrap
224 tests passing.

Open source

Nyx is open source under Apache 2.0. The standard library, runtime, and all products are free to use and modify.

GitHub Contributing Guide

Try nyx-kv

nyx-kv is running on this server right now. It speaks the Redis protocol — connect with any Redis client.

Connect with redis-cli
$ redis-cli -h nyxlang.com -p 6380
> PING
PONG
> SET hello world
OK
> GET hello
"world"
Or from Python
import redis
r = redis.Redis(host='nyxlang.com', port=6380)
r.set('greeting', 'hello from python')
print(r.get('greeting'))
Or from Node.js
import Redis from 'ioredis';
const r = new Redis({ host: 'nyxlang.com', port: 6380 });
await r.set('greeting', 'hello from node');
console.log(await r.get('greeting'));
Supported commands
PING  SET  GET  DEL  EXISTS  KEYS  EXPIRE  TTL
INCR  DECR  MSET  MGET  DBSIZE  FLUSHDB  INFO

This is a public demo server. Do not store sensitive data.