isolated-functions
March 27, 2026 Β· View on GitHub
π Prevent usage of variables from outside the scope of isolated functions.
πΌπ« This rule is enabled in the β
recommended config. This rule is disabled in the βοΈ unopinionated config.
Some functions need to be isolated from their surrounding scope due to execution context constraints. For example, functions passed to makeSynchronous() are executed in a worker or subprocess and cannot access variables from outside their scope. This rule helps identify when functions are using external variables that may cause runtime errors.
Common scenarios where functions must be isolated:
- Functions passed to
makeSynchronous()(executed in worker) - Functions that will be serialized via
Function.prototype.toString() - Server actions or other remote execution contexts
- Functions with specific JSDoc annotations
By default, this rule uses ESLint's language options globals and allows global variables (like console, fetch, etc.) in isolated functions, but prevents usage of variables from the surrounding scope.
Examples
import makeSynchronous from 'make-synchronous';
const url = 'https://example.com';
const getText = makeSynchronous(async () => {
const response = await fetch(url); // β 'url' is not defined in isolated function scope
return response.text();
});
// β
Define all variables within isolated function's scope
const getText = makeSynchronous(async () => {
const url = 'https://example.com'; // Variable defined within function scope
const response = await fetch(url);
return response.text();
});
// β
Alternative: Pass as parameter
const getText = makeSynchronous(async (url) => { // Variable passed as parameter
const response = await fetch(url);
return response.text();
});
console.log(getText('https://example.com'));
const foo = 'hi';
/** @isolated */
function abc() {
return foo.slice(); // β 'foo' is not defined in isolated function scope
}
// β
/** @isolated */
function abc() {
const foo = 'hi'; // Variable defined within function scope
return foo.slice();
}
Options
Type: object
functions
Type: string[]
Default: ['makeSynchronous']
Array of function names that create isolated execution contexts. Functions passed as arguments to these functions will be considered isolated.
selectors
Type: string[]
Default: []
Array of ESLint selectors to identify isolated functions. Useful for custom naming conventions or framework-specific patterns.
{
'unicorn/isolated-functions': [
'error',
{
selectors: [
'FunctionDeclaration[id.name=/lambdaHandler.*/]'
]
}
]
}
comments
Type: string[]
Default: ['@isolated']
Array of comment strings that mark functions as isolated. Functions with inline, block, or JSDoc comments tagged with these strings will be considered isolated. (Definition of "tagged": either the comment consists solely of the tag, or starts with it, and has an explanation following a hyphen, like // @isolated - this function will be stringified).
{
'unicorn/isolated-functions': [
'error',
{
comments: [
'@isolated',
'@remote'
]
}
]
}
overrideGlobals
Type: object
Default: undefined (uses ESLint's language options globals)
Controls how global variables are handled. When not specified, uses ESLint's language options globals. When specified as an object, each key is a global variable name and the value controls its behavior:
'readonly': Global variable is allowed but cannot be written to'writable': Global variable is allowed and can be read/written'off': Global variable is not allowed
{
'unicorn/isolated-functions': [
'error',
{
overrideGlobals: {
console: 'writable', // Allowed and writable
fetch: 'readonly', // Allowed but readonly
process: 'off' // Not allowed
}
}
]
}
Examples
Custom function names
{
'unicorn/isolated-functions': [
'error',
{
functions: [
'makeSynchronous',
'createWorker',
'serializeFunction'
]
}
]
}
Lambda function naming convention
{
'unicorn/isolated-functions': [
'error',
{
selectors: [
'FunctionDeclaration[id.name=/lambdaHandler.*/]'
]
}
]
}
const foo = 'hi';
function lambdaHandlerFoo() { // β Will be flagged as isolated
return foo.slice();
}
function someOtherFunction() { // β
Not flagged
return foo.slice();
}
createLambda({
name: 'fooLambda',
code: lambdaHandlerFoo.toString(), // Function will be serialized
});
Default behavior (using ESLint's language options)
// Uses ESLint's language options globals by default
makeSynchronous(async () => {
console.log('Starting...'); // β
Allowed if console is in language options
const response = await fetch('https://api.example.com'); // β
Allowed if fetch is in language options
return response.text();
});
Allowing specific globals
{
'unicorn/isolated-functions': [
'error',
{
overrideGlobals: {
console: 'writable', // Allowed and writable
fetch: 'readonly', // Allowed but readonly
URL: 'readonly' // Allowed but readonly
}
}
]
}
// β
All globals used are explicitly allowed
makeSynchronous(async () => {
console.log('Starting...'); // β
Allowed global
const response = await fetch('https://api.example.com'); // β
Allowed global
const url = new URL(response.url); // β
Allowed global
return response.text();
});
makeSynchronous(async () => {
const response = await fetch('https://api.example.com', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}` // β 'process' is not in allowed globals
}
});
const url = new URL(response.url);
return response.text();
});
// β Attempting to write to readonly global
makeSynchronous(async () => {
fetch = null; // β 'fetch' is readonly
console.log('Starting...');
});
Predefined global variables
To enable a predefined set of globals, use the globals package similarly to how you would use it in languageOptions (see ESLint docs on globals):
import globals from 'globals'
export default [
{
rules: {
'unicorn/isolated-functions': [
'error',
{
globals: {
...globals.builtin,
...globals.applescript,
...globals.greasemonkey,
},
},
],
},
},
]