Performance

js-cgi uses the CGI model — a new process is spawned for each request. Understanding this helps you write fast scripts.

CGI Overhead

Each request involves:

  1. Apache spawns the js-cgi process (~1ms)
  2. js-cgi runtime initialises (~1ms)
  3. Extensions are loaded (~1ms per extension)
  4. Your script executes
  5. Process exits

Total overhead is typically 3-5ms on modern hardware. For most web applications this is negligible.

Tips for Fast Scripts

Open and close databases efficiently

// Good — open once, use multiple times, close once
const db = sqlite.open("/var/www/data/app.db");
const user = db.queryOne("SELECT * FROM users WHERE id = ?", [userId]);
const posts = db.query("SELECT * FROM posts WHERE user_id = ?", [userId]);
db.close();

// Bad — opening and closing for each query
const db1 = sqlite.open("/var/www/data/app.db");
const user = db1.queryOne("SELECT * FROM users WHERE id = ?", [userId]);
db1.close();
const db2 = sqlite.open("/var/www/data/app.db");
const posts = db2.query("SELECT * FROM posts WHERE user_id = ?", [userId]);
db2.close();

Avoid reading large files unnecessarily

// Good — check before reading
if (file.exists("/var/www/cache/page.html")) {
    const cached = file.read("/var/www/cache/page.html");
    print(cached);
}

// Consider file size before reading
const size = file.size("/var/www/uploads/data.csv");
if (size > 10 * 1024 * 1024) {
    response.setStatus(413);
    print("File too large to process");
}

Use appropriate memory limits

Don't set memory limits higher than needed. Lower limits catch runaway scripts earlier:

# API that processes small JSON payloads
memory_limit = 32M

# Page that renders large datasets
memory_limit = 128M

Minimise HTTP extension calls

Each http.get() or http.post() call blocks until the remote server responds. Minimise external calls per request:

// Consider caching external API responses
const CACHE_FILE = "/var/www/cache/api-data.json";
const CACHE_TTL = 300; // 5 minutes

let data;
if (file.exists(CACHE_FILE)) {
    const age = (Date.now() / 1000) - (file.size(CACHE_FILE) > 0 ? JSON.parse(file.read(CACHE_FILE)).ts : 0);
    if (age < CACHE_TTL) {
        data = JSON.parse(file.read(CACHE_FILE)).data;
    }
}

if (!data) {
    const res = http.get("https://api.example.com/data");
    data = JSON.parse(res.body);
    file.write(CACHE_FILE, JSON.stringify({ ts: Math.floor(Date.now() / 1000), data }));
}

When CGI Isn't Enough

If you're handling hundreds of requests per second on a single server and the CGI overhead matters, js-cgi supports FastCGI mode. This keeps worker processes persistent between requests, eliminating startup overhead:

js-cgi --fastcgi /var/run/js-cgi.sock --workers 4

Point Nginx or Apache at the socket with fastcgi_pass or mod_proxy_fcgi. See the Deployment docs for full configuration examples.

Benchmarks

ScenarioTypical Response Time
Simple HTML page (print only)< 5ms
SQLite query + JSON response5-10ms
Page with includes + SQLite8-15ms
External HTTP call + response50-500ms (network dependent)
Was this page helpful?