Back to writing
Glib Rulev
Glib Rulev

Protect Your Node.js App by Limiting Request Size

Protect Your Node.js App by Limiting Request Size

When building Node.js applications, it’s easy to overlook one simple but critical security measure: controlling the size of incoming HTTP requests.

Unrestricted payload sizes can lead to denial-of-service (DoS) attacks, memory exhaustion, or even crashes caused by resource-intensive parsing. Whether you’re accepting JSON, form data, or file uploads, setting size limits helps ensure your app stays stable, secure, and performant.

In this post, we’ll look at why request size limits matter, how to implement them in Fastify and native HTTP servers, and share best practices for setting them up correctly.

🚨 Why Request Size Limits Matter

Letting users send unlimited-size requests is dangerous. A large payload can:

  • Eat up memory and CPU
  • Block event-loop
  • Crash your app or make it unresponsive
  • Enable attackers to perform DoS attacks

For example, a huge JSON body with deeply nested objects can overwhelm your parser and cause delays or timeouts.

🚧 What Are Request Size Limits?

Request size limits define the maximum amount of data your server accepts in an HTTP request-body, headers, or the entire payload. In Node.js apps, especially those accepting JSON or file uploads, these limits help prevent abuse.

Frameworks like Fastify provide built-in options. If you’re using the native Node.js http module, you’ll need to handle it manually.

🔧 How to Set Limits in Node.js

Fastify

Fastify, a high-performance framework for Node.js, provides built-in options to limit request body sizes via the bodyLimit parameter. Additionally, for file uploads, the @fastify/multipart plugin allows specific file size constraints, with a default file size limit of 1048576 bytes (1MiB) for security reasons.

const fastify = require('fastify')({ bodyLimit: 1048576 }); // 1MB global body limit

const multipart = require('@fastify/multipart');
fastify.register(multipart, {
  limits: { fileSize: 1_000_000 } // 1MB per file
});

fastify.post('/upload', async (req, reply) => {
  try {
    const data = await req.file();
    return { filename: data.filename };
  } catch (err) {
    if (err instanceof fastify.multipartErrors.RequestFileTooLargeError) {
      return reply.code(413).send({ error: 'File too large' });
    }
    throw err;
  }
});

You can also override these limits per route - for instance, increasing the size only for upload endpoints.

Native Node.js HTTP Server

If you’re not using a framework, you’ll need to manually inspect incoming data and terminate the request if it exceeds your threshold:

const http = require('http');

http.createServer((req, res) => {
  let data = '';
  const maxSize = 50 * 1024; // 50KB

  req.on('data', chunk => {
    data += chunk;
    if (data.length > maxSize) {
      res.writeHead(413);
      res.end('Payload too large');
      req.destroy(); // close connection
    }
  });

  req.on('end', () => {
    res.writeHead(200);
    res.end('OK');
  });
}).listen(3000);

This gives you fine control, but remember: if you support complex data types or file uploads, writing your own logic gets tricky fast.

Reverse Proxies (e.g., Nginx)

For an additional layer of protection, set limits at the reverse proxy level. In Nginx, use:

http {
  client_max_body_size 1m; // Block large requests at the proxy
}

This prevents oversized requests from even hitting your Node.js process.

✅ Best Practices

  • Set context-specific limits: Use tighter limits for typical API endpoints, and larger ones only where needed (e.g. uploads).
  • Combine with rate limiting: Prevent users from flooding your app with repeated large requests.
  • Log and monitor: Keep track of how often large requests are blocked-it might uncover abuse or frontend issues.
  • Validate headers: Always inspect Content-Type and reject unexpected types before parsing.

⚠️ Common Mistakes to Avoid

  • Too low: A 20KB limit might break valid form submissions or JSON payloads.
  • Too high: Accepting 10MB+ requests without scrutiny opens the door to attacks or accidental overload.
  • Not handling errors: Uncaught exceptions or verbose error stacks can leak implementation details. Return clear but generic errors like 413 Payload Too Large.

✅ Conclusion

Limiting request sizes is one of the easiest and most effective ways to protect your Node.js server from abuse and instability. Whether you’re using Fastify, native HTTP, or proxy-layer settings, it only takes a few lines of code to implement - but can prevent major headaches down the road. Start with realistic defaults, test your endpoints with real data, and keep security top of mind.