Quick Start
Get up and running with NANO in under 5 minutes
Simple JavaScript App (5 min)
Create app.js
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === '/') {
return new Response('Hello from NANO!', {
headers: { 'Content-Type': 'text/plain' }
});
}
if (url.pathname === '/json') {
// Return a plain object (simplest, always works)
return {
status: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: 'Hello from NANO!',
runtime: 'nano-rs',
time: Date.now()
})
};
}
return new Response('Not Found', { status: 404 });
}
};
Create nano.json
{
"server": {
"port": 8080
},
"apps": [
{
"hostname": "localhost",
"entrypoint": "./app.js",
"limits": {
"workers": 2,
"memory_mb": 64
}
}
]
}
Run
nano-rs run --config nano.json
# Test the root endpoint curl http://localhost:8080/ Hello from NANO! # Test JSON endpoint curl http://localhost:8080/json {"message":"Hello from NANO!","time":1234567890}
WebAssembly App (10 min)
Compile Rust to WASM and call it from JavaScript.
Create Rust library
[package] name = "calc" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
Compile
cd wasm wasm-pack build --target web --out-dir ../pkg
Create JavaScript handler
import wasmModule from './pkg/calc.js';
let wasm;
let initPromise;
async function initWasm() {
wasm = await wasmModule();
}
export default {
async fetch(request) {
// Initialize on first request
if (!initPromise) {
initPromise = initWasm();
}
await initPromise;
const url = new URL(request.url);
if (url.pathname === '/add') {
const a = parseInt(url.searchParams.get('a') || '0');
const b = parseInt(url.searchParams.get('b') || '0');
const result = wasm.add(a, b);
return Response.json({ a, b, result });
}
if (url.pathname === '/fib') {
const n = parseInt(url.searchParams.get('n') || '10');
const result = wasm.fibonacci(n);
return Response.json({ n, result });
}
return new Response('Usage: /add?a=5&b=3 or /fib?n=20', {
headers: { 'Content-Type': 'text/plain' }
});
}
};
Create config
{
"server": { "port": 8080 },
"apps": [{
"hostname": "localhost",
"entrypoint": "./wasm-app.js",
"limits": { "workers": 2, "memory_mb": 128 }
}]
}
Run
nano-rs run --config nano-wasm.json
# Add two numbers curl "http://localhost:8080/add?a=5&b=3" {"a":5,"b":3,"result":8} # Calculate fibonacci curl "http://localhost:8080/fib?n=20" {"n":20,"result":6765}
Slivers: Create and Deploy (5 min)
Slivers are portable snapshots with ~267µs cold starts. Run an app, then create and deploy a sliver.
Create app
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === '/') {
return new Response('Hello from Sliver!', {
headers: { 'Content-Type': 'text/plain' }
});
}
if (url.pathname === '/version') {
return Response.json({
version: '1.0.0',
deployed: new Date().toISOString()
});
}
return new Response('Not Found', { status: 404 });
}
};
Step 1: Run the app for testing
{
"server": { "port": 8080 },
"apps": [{
"hostname": "localhost",
"entrypoint": "./sliver-demo.js",
"limits": { "workers": 2 }
}]
}
Terminal 1: nano-rs run --config dev.json
Step 2: Create the sliver
# Create sliver from the running app nano-rs sliver create localhost --output my-app-v1.sliver # Verify it was created ls -lh my-app-v1.sliver
Step 3: Stop the dev server
# In Terminal 1, press
Ctrl+C
Step 4: Run from sliver
nano-rs run --sliver my-app-v1.sliver --port 8080
curl http://localhost:8080/ Hello from Sliver! curl http://localhost:8080/version {"version":"1.0.0","deployed":"2026-01-01T12:00:00Z"}
Quick Command Reference
Commands
nano-rs run --config nano.json - Run with confignano-rs run --sliver app.sliver - Run from slivernano-rs sliver create localhost --output app.sliver - Create sliverTesting
curl http://localhost:8080/ - Basic testcurl -H "Host: api.example.com" ... - Multi-tenantcurl http://localhost:8080/json - JSON endpointNext Steps
Understanding Workers
What is a Worker?
A worker is a dedicated OS thread that:
- Owns one V8 isolate (JavaScript execution environment)
- Processes requests sequentially in a loop
- Cannot share isolates with other workers (V8 requirement)
Request Routing (Round-Robin)
NANO uses round-robin routing to distribute requests:
Request 1 → Worker 0 Request 2 → Worker 1 Request 3 → Worker 2 Request 4 → Worker 0 (wraps around)
Key Points:
- No shared state between workers (isolation)
- Same hostname can hit different workers
- Memory is per-isolate (4 workers = 4× memory)
Understanding the Logs
When you run NANO, you'll see two types of logs:
HTTP GET / → 200 in 5.23ms (worker: 0) HTTP GET /json → 200 in 3.45ms (worker: 1) HTTP GET /notfound → 404 in 1.20ms (worker: 2)
Worker 0 processed GET / → 200 in 5ms (isolate: worker_0_localhost) Worker 1 processed GET /json → 200 in 3ms (isolate: worker_1_localhost)
Log Fields
HTTP Access Log
method- GET, POST, etc.path- Request pathhost- Virtual hostnamestatus- HTTP code (200, 404...)worker_id- Which worker (0, 1, 2...)duration_ms- Total time
Worker Processing Log
worker_id- Thread (0, 1, 2...)isolate_id- V8 isolate namehostname- Tenantmethod/path- Requeststatus- Response codeduration_ms- JS exec time
Configuring Workers
{
"apps": [{
"hostname": "localhost",
"entrypoint": "./app.js",
"limits": {
"workers": 4,
"memory_mb": 128
}
}]
}
Low Traffic
1-2 workers
Standard
4 workers (default)
High Traffic
8-16 workers
Memory Warning: Each worker = 1 isolate. With 4 workers and 128MB limit, that's ~512MB total memory usage.
Understanding Logs
NANO uses structured JSON logging with request tracing. Each request generates multiple log entries showing the complete lifecycle.
Log Format
{
"ts": "2026-05-03T12:34:56.789Z",
"level": "INFO",
"message": "HTTP GET / - 200 in 5.23ms (worker: 0, isolate: iso_a3f7b2d8_00000001)",
"request_id": "req_a3f7b2d8",
"worker_id": 0,
"isolate_id": "iso_a3f7b2d8_00000001",
"hostname": "localhost",
"fields": {
"method": "GET",
"path": "/",
"status": 200,
"duration_ms": "5.23",
"worker_id": 0,
"isolate_id": "iso_a3f7b2d8_00000001"
}
}
Key Fields
request_id
Unique hash: req_{uuid_first_8}
worker_id
Worker thread number (0, 1, 2...)
isolate_id
Unique V8 isolate hash: iso_{uuid}_{counter}
hostname
Virtual host the request was routed to
Log Types
Debugging Isolates
Use the three-part combo for full request tracing:
See Debugging and Profiling NANO Isolates for complete guide.
Troubleshooting
"unknown field `port`"
Put port inside server: {"server": {"port": 8080}}
Port already in use
lsof -ti:8080 | xargs kill -9
"Cannot find module"
Use ./ prefix: "entrypoint": "./app.js"