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:
- Apache spawns the js-cgi process (~1ms)
- js-cgi runtime initialises (~1ms)
- Extensions are loaded (~1ms per extension)
- Your script executes
- 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
| Scenario | Typical Response Time |
|---|---|
| Simple HTML page (print only) | < 5ms |
| SQLite query + JSON response | 5-10ms |
| Page with includes + SQLite | 8-15ms |
| External HTTP call + response | 50-500ms (network dependent) |