
Learn how the new using keyword and Symbol.dispose replace try/finally for cleaner resource management in JavaScript. With ES2026 support details.
Martin Ferret
June 9, 2026
using in JavaScript: Automatic Resource ManagementFor years, JavaScript lacked a clean way to release a resource once you were done with it. Open a file, start a transaction, acquire a lock, and the cleanup was on you. The Explicit Resource Management proposal, now stable, fixes this by introducing the using keyword.
using SolvesWithout using, cleanup code relies on try/finally. It works, but it is verbose and easy to forget:
function processFile(path) {
const file = openFile(path);
try {
return file.read();
} finally {
file.close();
}
}
Handle three resources and you end up with three nested try/finally blocks. The actual logic drowns in plumbing.
using declares a variable whose resource will be released automatically when the block exits:
{
using file = openFile('data.txt');
console.log(file.read());
} // fileSymbol.dispose is called here, automatically
At the closing brace, the JavaScript engine calls fileSymbol.dispose. No finally needed. Whether the block exits normally or through an exception, cleanup happens.
For an object to work with using, it must implement Symbol.dispose. This is a new well-known symbol, in the same family as Symbol.iterator:
function openFile(path) {
const handle = lowLevelOpen(path);
return {
read() { return lowLevelRead(handle); },
Symbol.dispose {
lowLevelClose(handle);
}
};
}
Any object exposing this method can be declared with using. It is a simple contract, not a special class to extend.
await usingMany resources release asynchronously: closing a network connection, flushing a buffer, committing a transaction. For these, there is Symbol.asyncDispose and the await using form:
async function queryDatabase() {
await using conn = await openConnection();
return conn.query('SELECT * FROM users');
} // await connSymbol.asyncDispose runs here
The object must expose Symbol.asyncDispose, which returns a promise. The engine awaits it before continuing past the scope.
When multiple resources are declared in the same block, they are released in reverse order of declaration, like a stack:
{
using a = acquire('A');
using b = acquire('B');
using c = acquire('C');
} // dispose runs on c, then b, then a
This order matters. If c depends on b, you want c torn down first. Same logic as C++ destructors or stacked defer in Go.
SuppressedErrorIf the block throws an error and a dispose method also throws during cleanup, JavaScript loses neither. It wraps them in a SuppressedError:
try {
using resource = makeFlakyResource();
throw new Error('business failure');
} catch (e) {
console.log(e.error); // the original error
console.log(e.suppressed); // the dispose error
}
A real improvement over try/finally, where an error in finally silently overwrites the one from try.
DisposableStack HelperSometimes you build a list of resources dynamically or conditionally. DisposableStack (and its async sibling AsyncDisposableStack) lets you group several resources and release them in one go:
function setup() {
using stack = new DisposableStack();
const file = stack.use(openFile('data.txt'));
const lock = stack.use(acquireLock());
if (needsConnection()) {
stack.use(openConnection());
}
// if everything went well, hand ownership to the caller
return { file, lock, dispose: stack.move() };
}
stack.use(x) registers x for disposal. stack.move() transfers ownership elsewhere, which prevents automatic cleanup at the end of the current scope.
The proposal reached Stage 4 at the TC39 meeting in May 2025 and is part of ES2026. Concretely, here is what you can rely on right now.
Runtimes. Node.js 24 and above ship with native support, courtesy of the V8 13.6 upgrade. Older Node versions (18.18+, 20.4+) expose Symbol.dispose and Symbol.asyncDispose but do not parse the using syntax. Deno has supported it since 1.37, and Bun ships with it as well.
Browsers. Chrome and Edge picked it up around version 134. Safari has shipped it since 18.3. Firefox supports it in its recent versions through SpiderMonkey.
Tooling. TypeScript has known the syntax since 5.2 (September 2023) and can down-compile it for older targets. Babel 7.28 (June 2025) enabled it by default in @babel/preset-env, so a separate plugin is no longer needed.
In practice. If your backend runs on Node.js 24+, you can use using directly. On older LTS versions, TypeScript or Babel will transpile it for you. On the frontend, any modern bundler (Vite, Webpack, esbuild) handles it transparently, which means Angular, React, Vue, and NestJS projects can adopt it today without ceremony.
The one situation that still requires care: plain JavaScript shipped to older browsers or older Node runtimes without any transpilation. In that case, a polyfill like @shigen/polyfill-symbol-dispose or the disposablestack package fills the gap for the symbols, but the syntax itself still needs a transpiler.
using is not a piece of magic syntax. It is an explicit contract between the language and the objects that hold a resource: implement Symbol.dispose, and the engine handles cleanup. Real logic stays readable, cleanup errors are no longer swallowed, and the repetitive try/finally pattern disappears in most cases.
For the fullstack developer juggling database connections, files, and locks, this is one of the most practical additions to modern JavaScript, in the same league as async/await was in its day.
Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

`using` in JavaScript: Automatic Resource Management
Learn how the new using keyword and Symbol.dispose replace try/finally for cleaner resource management in JavaScript. With ES2026 support details.
Martin Ferret
Jun 9, 2026

State Management in React: useReducer, Context, and External Stores
Learn when to move beyond useState in React. This guide covers useReducer, the split-context pattern, external stores like Zustand, server state with TanStack Query, and useSyncExternalStore.
Aurora Scharff
Jun 4, 2026

Deploying Nuxt: Presets, Platforms, and Hybrid Rendering
How to deploy Nuxt to Vercel, Netlify, Cloudflare, and Node, with hybrid rendering via routeRules.
Reza Baar
Jun 3, 2026