Your bot or web app feels slow, and the temptation is to start "optimising" the code you think is the problem. Resist it — the slow part is almost never where you'd guess. This guide shows how to actually measure performance on a Falix server, using only the tools a panel host gives you. No fancy profiler GUI required; the humble ones find most problems.
| At a glance | |
|---|---|
| You need | A server running the Node.js application |
| Plan | Any — every technique here works on the free plan |
| Time | Twenty minutes |
Rule zero: measure, don't guess
Optimisation without measurement is just rearranging code and hoping. Before you change anything, get a number. After you change it, get the number again. If the number didn't move, undo the change — it wasn't the problem. Everything below is about getting honest numbers cheaply.
Timing slow code with console.time
The fastest way to answer "which part is slow" is to wrap the suspect in a labelled timer. Node prints the elapsed time straight to your Console:
console.time('db-query');
const rows = await db.all('SELECT * FROM users');
console.timeEnd('db-query'); // → db-query: 12.3ms
- Label every timer — you'll have several, and the label is how you tell them apart.
- Mind
await. For async work, thetimeEndmust run after theawait, or you'll time how long it took to start the work, not finish it (as above — theawaitis between them). console.timeLog('db-query')prints an intermediate reading without stopping the timer, handy inside a loop.
Sprinkle a few of these through a slow request and one line will dwarf the others. That line is your target.
Measuring a whole endpoint with curl
console.time measures time inside your app. To measure what a user actually feels — network plus app — hit the endpoint from your own machine with curl's timing template. Your app's public address and port are on the Network page:
curl -o /dev/null -s -w "connect: %{time_connect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" http://YOUR-ADDRESS:PORT/your/route
time_connect— how long to establish the connection (network/distance).time_starttransfer(TTFB, time to first byte) — connection plus however long your app took to produce the response.time_total— the whole round trip.
Read them together. If TTFB is high but your in-app console.time totals are low, the time is going somewhere between the request arriving and your handler — or the number is dominated by distance. If TTFB tracks your in-app timings, the app itself is the slow part, and console.time will tell you which function. That split — network vs. app — is the single most useful thing this measurement gives you.
💡 Tip: Run the
curla handful of times. The first hit can be cold (a connection warming up, a cache empty); the steady-state number after a few runs is the one that matters.
The memory dimension
Speed and memory are different problems. For a quick read, process.memoryUsage() hands you the numbers, and rss is the figure Falix compares to your limit:
setInterval(() => {
const mb = (n) => (n / 1024 / 1024).toFixed(1);
const m = process.memoryUsage();
console.log(`rss ${mb(m.rss)}MB | heapUsed ${mb(m.heapUsed)}MB`);
}, 60_000);
Memory that climbs and never falls is a leak, and hunting one is its own craft — the Finding Node.js memory leaks guide covers reading every field, the patterns that leak, and how to bisect to the culprit. Start there when memory, not speed, is the symptom.
Why --inspect and heap snapshots aren't practical here
You may read that the real way to profile Node is --inspect with Chrome DevTools, or capturing heap snapshots. Both run into the same wall on a panel host, and it's worth being honest about why:
--inspectis anodeflag, so it goes before the filename in the start command. Editing the full startup command is premium-only, and the Additional Arguments (NODE_ARGS) variable is appended after your filename — it reaches your script, notnode, so it can't enable the inspector.- Even with the flag on, you'd have to attach a browser on your machine to the inspector's debug port on the server. That's a local-tooling-plus-network setup a panel host isn't built to hand you.
So the practical toolkit here is the log-based one above: console.time, curl timing, and process.memoryUsage. It needs nothing special, works on free, and solves the large majority of real performance problems. For the deep end, the official Node.js diagnostics docs go further than a panel host can — good reading for when you've outgrown these tools.
The usual suspects
Once you've located the slow part, it's usually one of these:
- Blocking the event loop — synchronous work on the request path (
fs.readFileSync, a hugeJSON.parse, crypto in a loop). Move it to the async version; one blocked call stalls everything. - N+1 queries — a query per item in a loop instead of one query for all of them. Batch it.
- Missing
await— overlapping work that should be sequential, or a promise you forgot to wait on. - Recomputing the same expensive thing — cache the result (a bounded in-memory map, or Redis for anything shared across restarts).
Fix one, re-run your console.time and curl, and confirm the number actually dropped.
The Minecraft parallel
Running a Minecraft server instead? The same lesson — profile, don't guess — has a purpose-built tool there: spark, a profiler plugin that produces a shareable report naming whatever's eating the most tick time. Same philosophy, different runtime. See Fixing Minecraft lag and reading a spark report.