Skip to content

Unlock the Full Power of Node.js in Bruno with Native VM Support (Beta)

At Bruno, we're constantly striving to empower developers with the best tools for API testing and development. Today, we're thrilled to announce a significant leap forward in how you can extend Bruno's capabilities: Native Node VM Support for JavaScript execution in Developer Mode. 

Native Node VM support is currently in Beta. While we're excited about its potential, please be aware that it's under active development. Your feedback is crucial!

Understanding Sandboxes: Why We Need Them

Before diving into the new features, let's understand a fundamental concept: sandboxes. In computing, a sandbox is an isolated environment where programs can be executed without affecting the host system. Think of it like a playpen for code – it can run, but its actions are contained within the designated area.

In the context of Bruno and executing user scripts, sandboxes are critical for a few reasons:

  • Security: They prevent malicious or buggy scripts from accessing or damaging your local file system, network, or other applications.
  • Stability: They ensure that errors or crashes in a user script don't bring down Bruno itself.
  • Isolation: Each script runs independently, preventing unintended side effects between different requests or environments.

The Previous Approach: vm2

Previously, Bruno utilized the vm2 library as its Node.js sandbox environment. vm2 offered a secure way to execute JavaScript scripts within Bruno and allowed you to leverage many third-party libraries. With vm2, you could integrate popular libraries to perform various tasks directly within your Bruno pre-request or post-response scripts.

However, vm2, being a third-party library itself, came with inherent limitations:

  • Restricted Node.js Internals: vm2 couldn't provide full access to Node.js's core modules and internal functionalities. This meant certain advanced Node.js operations or integrations were simply not possible.
  • Third-Party Dependency: Relying on an external library introduced an additional layer of abstraction and potential compatibility issues.

While vm2 served its purpose well, it ultimately placed a ceiling on the true power of Node.js that could be harnessed within Bruno.

The Solution: Native Node VM Support

With the introduction of Native Node VM support, Bruno now leverages Node.js's own built-in vm module. This is a game-changer because it:

  • Provides Complete Node.js Context: You get access to the full suite of Node.js core modules (like fs, https, url, etc.), allowing you to interact with file systems, network protocols, and other low-level functionalities directly from your scripts.
  • Seamless Library Integration: Libraries that depend on Node.js internals or specific global objects can now run without issues, giving you unparalleled flexibility.
  • Unprecedented Control: From complex database interactions to advanced data processing and custom integrations, the possibilities for extending your API tests and pre/post-request scripts are virtually limitless.

This new support essentially provides a truly isolated environment that behaves almost identically to a regular Node.js process, allowing your scripts to operate with the same power and flexibility as if they were running outside of Bruno, but still within a secure sandbox.

How to Work with Native Node VM in Bruno (Beta)

1. Enable Beta Support in Bruno

To start using Native Node VM, you first need to ensure you're running a latest version of Bruno. You need to explicitly enable it within Bruno's  Preferences > Beta settings. (refer below screenshot.)

Screenshot 2025-10-27 at 4.59.53 PM

Once enabled, you can then write your scripts using standard Node.js require() syntax for both core modules and installed third-party packages.

2. Code Examples

Here are a few examples showcasing the power of Native Node VM support:

Example 1: Robust MySQL Database Interactions

This script demonstrates how you can connect to a MySQL database, execute a query, and log the results directly within your Bruno script. This is incredibly useful for setting up test data before a request or validating data after a request.

Before jumping to code snippet and using external libraries in Bruno, please read external libraries config on official docs to understand how it actually works and configurations you have to add in Bruno.

const mysql = require("mysql2/promise");
			
	async function testMySql() {
	  let connection;
	  try {
	    // Connect to your MySQL database
	    connection = await mysql.createConnection({
	      host: "localhost",       // Or your remote database host
	      user: "root",
	      password: "password",
	      database: "testdb",
	    });
	    console.log("MySQL connection established.");
			
	    // Run a test query to fetch the current time
	    const [rows] = await connection.query("SELECT NOW() AS current_time");
	    console.log("Current DB time:", rows[0].current_time);
			
	  } catch (err) {
	    console.error("MySQL operation failed:", err.message);
	    if (err.code === 'ER_ACCESS_DENIED_ERROR') {
	      console.error('Hint: Check your MySQL username and password.');
	    } else if (err.code === 'ECONNREFUSED') {
	      console.error('Hint: MySQL server might not be running or host/port is incorrect.');
	    }
	  } finally {
	    // Ensure the connection is always closed
	    if (connection) {
	      await connection.end();
	      console.log("MySQL connection closed.");
	    }
	  }
	}
			
	// Execute the database interaction function
	await testMySql();

Diff from vm2 environment: This code would largely work in vm2 if mysql2/promise was installed and didn't rely on deep Node.js internals. However, the stability and full access to Node.js APIs (if needed for more complex scenarios, e.g., connecting to a Unix socket or SSL/TLS specific options) are significantly enhanced with native VM.

Example 2: Advanced PDF Processing with Node.js Modules

This example showcases downloading a PDF using Node's native https module, writing it to a temporary file using fs (File System), and then parsing it with `pdf2json`. This demonstrates true interaction with the operating system and network, capabilities often limited or unavailable in vm2.

const PDFParser = require("pdf2json");
	
	async function parsePdfFromResponse() {
	  try {
	    // Assuming 'res' (Bruno response object) is available in a Post-response script
	    // and its body contains the raw PDF data.
	    const rawPdfData = res.getBody(); // Get the raw response body from Bruno
	    
	    // Convert raw data (Buffer) to a format pdf2json can parse
	    const buffer = Buffer.from(rawPdfData); 
	
	    const pdfParser = new PDFParser();
	
	    // Use a Promise to handle async parsing events
	    const pdfData = await new Promise((resolve, reject) => {
	      pdfParser.on("pdfParser_dataError", errData => {
	        console.error("PDF parsing error:", errData.parserError);
	        reject(errData.parserError);
	      });
	      pdfParser.on("pdfParser_dataReady", pdfData => {
	        console.log("PDF parsed successfully.");
	        // Example: Log the number of pages or raw text content
	        // console.log('Number of pages:', pdfData.Pages.length);
	        // console.log('First page text:', pdfParser.getRawTextContent().slice(0, 200) + '...');
	        resolve(pdfData);
	      });
	      
	      pdfParser.parseBuffer(buffer); // Parse the PDF directly from the buffer
	    });
	
	    console.log("Parsed PDF Data:", pdfData);
	    // You can now extract data from pdfData and perform assertions in Bruno
	    // e.g., bruno.assert(pdfData.Pages.length > 0, "PDF has pages");
	
	  } catch (error) {
	    console.error('PDF processing failed:', error.message);
	  }
	}
	
	// Execute the PDF processing function (e.g., in a Bruno Post-response script)
	await parsePdfFromResponse();

Checkout the complete code snippet for pdf2json example from here.

Diff from vm2 environment: This entire example would be problematic in a vm2 environment. The ability to directly use Node's native https module for network requests (if you were downloading first as in the previous example) and, critically, the fs (File System) module to write and read local files are fundamental to many complex scripts' operations and were largely unavailable or highly restricted in vm2.

Parsing directly from a Buffer within Bruno's response object also highlights the flexibility now available.

Try the Demo Yourself

We’ve published the full working collection on GitHub. You can either clone this or simply click the Fetch in Bruno button below!

 

 

Conclusion

Native Node VM support is a monumental step in making Bruno an even more versatile and powerful tool for developers. By providing full access to Node.js core modules and seamless integration of third-party libraries, it significantly expands the possibilities for what you can achieve within your pre-request and post-response scripts.

We're excited to see what you'll build with this new capability!

We Need Your Feedback!

As this feature is in Beta, your feedback is invaluable! Please report any issues, bugs, or suggestions on our GitHub repository. Your contributions help us refine and stabilize this powerful new feature for everyone.