Claude Skills Guide

The Node.js vm module is a powerful built-in module that provides APIs for compiling and executing code in isolated contexts. Whether you need to run user-provided scripts, create sandboxed environments, or implement template rendering engines, the vm module offers essential capabilities for secure code execution. This guide shows you how to use Claude Code to work effectively with the Node.js vm module, from basic script compilation to advanced sandboxing patterns.

Understanding the VM Module Fundamentals

The vm module allows you to compile and run JavaScript code within specific contexts, providing isolation from the main Node.js environment. This isolation is crucial when executing untrusted code or when you need to create separate execution contexts with different global variables.

Claude Code can help you understand the core vm APIs by generating examples and explaining the behavior of each method. Start by familiarizing yourself with the primary functions: vm.runInThisContext(), vm.runInNewContext(), and vm.createContext().

const vm = require('vm');

// Running code in the current context
const script = new vm.Script('const x = 42; console.log(x * 2);');
script.runInThisContext(); // Outputs: 84

// Running code in a new isolated context
const context = { count: 0 };
vm.createContext(context);
script.runInContext(context);
console.log(context.count); // Access variables from isolated context

Claude Code excels at explaining how these different methods behave and when to use each one. Ask Claude to generate variations that demonstrate context isolation, variable leakage prevention, and timeout handling.

Secure Sandbox Execution Patterns

Creating secure sandboxed environments is one of the most common use cases for the vm module. However, implementing proper security requires careful consideration of potential escape vulnerabilities and resource constraints.

const vm = require('vm');

function createSandbox(timeout = 1000) {
  const sandbox = {
    console: {
      log: (...args) => console.log('[sandbox]', ...args),
      error: (...args) => console.error('[sandbox]', ...args),
    },
    setTimeout: null, // Disabled for security
    setInterval: null,
    setImmediate: null,
    process: undefined, // Prevent process access
    require: undefined, // Disable require
    global: undefined,
  };
  
  vm.createContext(sandbox);
  return sandbox;
}

function executeSafely(code, sandbox) {
  try {
    const script = new vm.Script(code, {
      filename: 'sandbox.js',
      timeout: 1000,
    });
    return script.runInContext(sandbox, { timeout: 1000 });
  } catch (error) {
    return { error: error.message };
  }
}

const sandbox = createSandbox();
executeSafely('console.log("Hello from sandbox!");', sandbox);

Claude Code can help you extend this pattern with additional security measures, such as restricting access to filesystem and network APIs, implementing memory limits, and adding comprehensive error handling for different types of sandbox escapes.

Dynamic Template Rendering with VM

The vm module serves as an excellent foundation for building dynamic template rendering systems. By creating custom contexts with available variables, you can render templates with controlled access to JavaScript functionality.

const vm = require('vm');

function renderTemplate(template, data) {
  const context = {
    ...data,
    // Safe helper functions available in templates
    upper: (str) => String(str).toUpperCase(),
    lower: (str) => String(str).toLowerCase(),
    repeat: (str, times) => String(str).repeat(times),
    json: (obj) => JSON.stringify(obj, null, 2),
  };
  
  vm.createContext(context);
  
  // Wrap template in a function for evaluation
  const wrappedCode = `(function() { return \`${template}\`; })()`;
  const script = new vm.Script(wrappedCode);
  
  return script.runInContext(context);
}

const template = 'Hello, {{ upper(name) }}! Your items: {{ json(items) }}';
const data = { name: 'World', items: ['apple', 'banana', 'cherry'] };

console.log(renderTemplate(template, data));
// Output: Hello, WORLD! Your items: ["apple","banana","cherry"]

This pattern is particularly useful when building CMS systems, email templates, or configuration generators where users need to inject dynamic values into text templates. Claude Code can help you extend this with more sophisticated template syntax, loops, and conditionals.

Code Compilation and Caching Strategies

For applications that repeatedly execute similar code, compiling scripts once and running them multiple times provides significant performance benefits. Understanding when and how to cache compiled scripts is essential for optimization.

const vm = require('vm');

class ScriptCache {
  constructor() {
    this.cache = new Map();
  }
  
  getOrCreate(code, contextOptions = {}) {
    const key = this.hashCode(code);
    
    if (!this.cache.has(key)) {
      const script = new vm.Script(code, {
        produceCachedData: true,
      });
      this.cache.set(key, { script, contextOptions });
    }
    
    return this.cache.get(key);
  }
  
  hashCode(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash;
    }
    return hash.toString(36);
  }
  
  run(code, context) {
    const { script, contextOptions } = this.getOrCreate(code, contextOptions);
    vm.createContext(context);
    return script.runInContext(context);
  }
}

const cache = new ScriptCache();

// First compile - takes time
const start1 = Date.now();
cache.run('x * 2', { x: 21 });
console.log('First run:', Date.now() - start1, 'ms');

// Subsequent runs use cached compiled script
const start2 = Date.now();
cache.run('x * 2', { x: 21 });
console.log('Cached run:', Date.now() - start2, 'ms');

Claude Code can help you implement more sophisticated caching strategies, including context reuse, precompilation of common patterns, and memory management for large-scale applications.

Handling Timeouts and Resource Limits

When executing untrusted or potentially infinite code, implementing proper timeout and resource management is critical. The vm module provides built-in timeout functionality, but combining it with other safeguards creates more robust execution environments.

const vm = require('vm');

function executeWithLimits(code, limits = {}) {
  const { timeout = 1000, memoryLimit = 128 * 1024 * 1024 } = limits;
  
  const sandbox = { 
    result: undefined,
    error: undefined,
  };
  
  vm.createContext(sandbox);
  
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error(`Execution timeout after ${timeout}ms`));
    }, timeout);
    
    try {
      const wrappedCode = `
        try {
          result = (function() { ${code} })();
        } catch (e) {
          error = e.message;
        }
      `;
      
      const script = new vm.Script(wrappedCode);
      const result = script.runInContext(sandbox, { timeout });
      
      clearTimeout(timer);
      resolve({ 
        result: sandbox.result, 
        error: sandbox.error,
      });
    } catch (error) {
      clearTimeout(timer);
      reject(error);
    }
  });
}

async function main() {
  try {
    const output = await executeWithLimits(`
      let sum = 0;
      for (let i = 0; i < 1000000; i++) {
        sum += i;
      }
      return sum;
    `, { timeout: 2000 });
    
    console.log('Result:', output.result);
  } catch (error) {
    console.error('Execution failed:', error.message);
  }
}

main();

Best Practices and Common Pitfalls

Working with the vm module requires awareness of several important considerations. Claude Code can help you avoid common mistakes and implement security best practices.

First, never underestimate the difficulty of creating truly secure sandboxes. The vm module provides isolation at the JavaScript level, but determined attackers can potentially escape. Always assume that sandboxed code can access the host system and design accordingly. For truly untrusted code, consider using containerization or separate processes.

Second, be mindful of resource consumption. Even simple-looking code can consume significant CPU or memory. Implement comprehensive limits and monitor resource usage in production environments.

Third, prefer vm.runInNewContext() over modifying the global object directly when you need isolation. This approach is more explicit and less prone to accidental data leakage.

Conclusion

The Node.js vm module is an essential tool for scenarios requiring code compilation, sandboxing, or dynamic execution. By combining Claude Code’s assistance with these patterns, you can build secure, performant systems for template rendering, plugin systems, and user code execution. Remember to always prioritize security when executing untrusted code, and use Claude Code to explore edge cases and advanced patterns as your requirements evolve.

Built by theluckystrike — More at zovo.one