← Back to Blog
Node.jsBackendBangkok

Scaling Node.js Backends for Bangkok Business Applications

14 May 2026 · by Yunmin Shin

When Does Your Node.js Backend Need Scaling Attention?

A well-written Node.js backend handles thousands of concurrent connections efficiently. But certain patterns — blocking the event loop, unmanaged memory growth, improper async error handling — cause performance degradation long before you hit hardware limits. This shows up fast in the kind of applications we build most: a restaurant's LINE ordering backend during a Friday dinner rush, or a clinic's appointment API when a promotion goes out to a LINE OA broadcast list of a few thousand followers at once.

These tips apply to Node.js backends in any form: Next.js custom servers, standalone Express/Fastify APIs, or serverless functions running on the Node.js runtime.

How Does the Node.js Event Loop Work?

Node.js is single-threaded and runs on an event loop. I/O operations — database queries, file reads, HTTP requests — are non-blocking, so Node.js keeps serving other requests while waiting on them. CPU-intensive operations, however, block the event loop entirely, freezing the application for every other user at once.

The clearest example we run into is image processing. A clinic site accepting before/after treatment photo uploads, or a restaurant menu editor resizing dish photos, is doing genuinely CPU-heavy work. Resizing a batch of images synchronously in a request handler will stall every other request hitting that server in the meantime — including, awkwardly, the LINE webhook that's supposed to respond within a few seconds or LINE will retry the delivery and you'll process the same order twice. Move image resizing, PDF generation, or any encryption/compression work to Worker Threads or a separate queue-backed service, never the main request thread.

What Are the Most Common Performance Mistakes?

Blocking the event loop with synchronous file system calls (fs.readFileSync, JSON.parse on large objects). Use async alternatives everywhere.

Unhandled promise rejections. Add a global handler and make sure every async function either catches its own errors or is called inside a try/catch block. In newer Node.js versions, unhandled rejections can crash the entire process — which, for a webhook endpoint receiving LINE messages, means every subsequent order silently fails until someone notices and restarts the service.

Memory leaks from event listener accumulation, unbounded global state, or circular references. This is a real risk in long-running order-tracking or booking-session state if you're not careful — use Node's built-in memory profiler, monitor heap usage in production, and set a process memory limit with an automatic restart if it's exceeded.

Synchronous middleware in Express that blocks the event loop for every request. Convert it to async and propagate errors with next(error) instead of throwing synchronously.

How Do You Handle Webhook Reliability?

LINE's Messaging API — the backbone of most restaurant ordering and clinic booking-confirmation flows in Bangkok — expects your webhook endpoint to respond within a few seconds. If it doesn't, LINE retries the delivery, and if your handler isn't idempotent, you end up creating duplicate orders or double-booking a slot from a single customer action. The fix is straightforward but easy to skip under deadline pressure: acknowledge the webhook immediately (respond 200 as soon as you've validated and queued the event), then do the actual order-creation or booking logic asynchronously, keyed on LINE's message ID or a request idempotency key so a retried delivery is a no-op rather than a duplicate.

How Do You Handle Database Query Performance?

Database queries are the most common bottleneck in Node.js backends. Apply these practices:

  • Index foreign keys and frequently filtered columns. An unindexed query on a large table — a growing table of restaurant orders or clinic appointments is exactly this — is orders of magnitude slower than an indexed one.
  • Use connection pooling. Opening a new database connection per request is expensive, and it's a mistake we see often in serverless setups hitting Supabase or Postgres directly. A pool of 10–20 connections handles hundreds of concurrent requests efficiently; for serverless functions, use a pooler (Supabase's built-in pgBouncer pooler, for example) rather than opening direct connections per invocation.
  • Avoid N+1 queries. Fetching a list of orders and then fetching the customer for each order in a loop makes N+1 database calls. Use JOINs or batch fetching instead — this matters more than it sounds once an order list has line items, a customer record, and a delivery address all joined together.
  • Set query timeouts. Long-running queries without timeouts hold connections open and degrade overall database performance for every other request.

How Do You Scale a Node.js Process?

Node.js uses one CPU core by default. The cluster module forks the process across all available cores, and PM2 — a popular process manager — handles this automatically with the -i max flag. This is the right approach if you're running on a VPS, which is still common for Bangkok small-business clients on a fixed monthly budget rather than pay-per-use cloud infrastructure.

For serverless architectures (Vercel, AWS Lambda), scaling is handled by the platform. Focus instead on minimizing cold start time — reduce imports, avoid large initializations at module load time, and keep function code lean. Cold starts matter more than usual for a LINE webhook handler, since a slow cold start eats directly into the few seconds LINE gives you before it decides to retry.

What Monitoring Should You Set Up?

At minimum, monitor CPU usage, memory usage, event loop lag, HTTP error rates (4xx and 5xx), and response time p95/p99. Tools like Datadog or New Relic provide this, but for Bangkok small businesses on limited budgets, Vercel Analytics plus Sentry's free tier cover the essentials — error tracking on the webhook and booking endpoints specifically, since those are the paths where a silent failure directly costs a business a customer.

Ready to Build Something Fast?

Get a free quote. We reply within 24 hours.

Ready to build something fast and scalable?

Get a free project quote. We reply within 24 hours.

Get a Free Quote →