deoptexplorer-vscode shows you why V8 threw away your optimized function
A VS Code extension to visualize deoptimizations in your JavaScript and TypeScript code running in V8 (i.e., NodeJS, Edge, Chrome, etc.).
At a glance
- What is it?
- deoptexplorer-vscode is a Microsoft VS Code extension that reads a V8 trace log and turns it into views of deoptimizations, inline cache evolution, function states, V8 maps and CPU profiles. It ships with the dexnode command line tool that produces the log, it is MIT licensed, and its newest release tag is v1.1.2 from 2023-05-31.
- Who is it for?
- deoptexplorer-vscode fits a performance engineer chasing a JavaScript regression that only shows up after the optimizing compiler gives up, since the deoptimization and inline cache views explain why a function keeps falling back to the interpreter, and the map view shows which property assignment created a shape change.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A tool for people who already know what V8 is doing
deoptexplorer-vscode is a VS Code extension to inspect deoptimizations, inline caches, function states, V8 maps and CPU profiling data for JavaScript and TypeScript code running in V8, in Edge, Chrome, NodeJS and similar runtimes.
The README is honest about who it is for. The tool is primarily designed for advanced users who have an understanding of V8's internals. It does not provide recommendations for performance improvements, but it does give you access to information you can use to make informed decisions about the performance of your code.
That framing matters. There is no guided workflow, no automatic diagnosis and no suggestion list. What there is, is a set of views over a trace log that a human expert reads to form a hypothesis about why a function is slow. The extension is the instrument panel, not the mechanic.
The repository lives under the microsoft organisation, and the package is published by rbuckton with a display name of deoptexplorer-vscode. It requires a fairly recent VS Code, with the engine field set to ^1.90.0, and the compiled entry point is ./dist/extension.js.
The release history is worth noting for anyone planning to depend on it. The tagged versions are v1.1.0 on 2023-05-19, v1.1.1 and v1.1.2 both on 2023-05-31, while the last push to the repository was on 2026-10-02, so work continues in the tree even though the published releases are three years old.
Five views over the same log
The information the extension provides falls into five categories, and each has its own view.
CPU Profiles reads trace file output from the --prof command line option and presents it as a tree view with Top Down, which is the call tree, Bottom Up and Flat views, similar to the Chrome Dev Tools. Deoptimizations records when the optimizing compiler switches back to the interpreter to collect type feedback that is then used to patch a function when different types are encountered. Function State shows whether a function was executed often enough to be optimized rather than being run purely in the interpreter.
The Inline Cache view is the ICS tree view, where you navigate IC events and use editor decorations and hover information to see how an inline cache evolves based on the types of values the interpreter and the optimizing compiler encounter.
Maps is the fifth, and the most V8 specific. V8 tracks the layout of objects in memory in what it calls a Map, which is not to be confused with the JavaScript Map object. The extension lets you view the maps encountered by an inline cache and trace each property in a map back to the function that assigned it, with the stated purpose of investigating and reducing unnecessary polymorphism. You can also peek at the maps associated with an IC event.
That tracing of a property back to the assigning function is the feature that makes the maps view more than a curiosity. Polymorphism in an inline cache is usually caused by a property being assigned different types somewhere, and the map view is the shortest route to the code responsible.
dexnode produces the log, and the flags are the interesting part
The extension reads a V8 log file, and the easiest way to generate a log compatible with your current NodeJS install is the dexnode command line utility published on npm. It wraps the existing node executable to provide the command line options needed to generate a V8 log the extension can consume.
Installing it is a global install.
npm install --global dexnodeRunning your script through it is then a single command.
# NodeJS (via global install)
dexnode myscript.js
# NodeJS (via `npm exec`)
npm exec dexnode myscript.js
# Deno (via `deno run`)
deno run -A npm:dexnode myscript.jsThe Deno example is worth noting, because it means the same tool works for a runtime that is not Node at all, as long as it can run an npm package.
The full option list shows what the tool does under the hood, because each inclusion flag maps to one of the log contents the extension reads.
dexnode [options] [--] <executable> [executable_options]
options:
-h --help print this message
--no-maps exclude v8 maps from log
--no-ics exclude ics from log
--no-deopts exclude deopts from log
--no-profile exclude cpu profile from log
--no-sources exclude sources from log
--no-quiet write dexnode messages to stdout (default)
--maps include v8 maps in log (default)
--ics include ics in log (default)
--deopts include deopts in log (default)
--profile include cpu profile in log (default)
--sources include sources in log (default)
--quiet do not write dexnode messages to stdout
--out FILE write all log output to FILE (default: isolate-<pid>-<isolate id>-v8.log)
-- pass all remaining arguments to nodeEvery category can be excluded, which is the practical lever. A log with maps and sources disabled is a fraction of the size of a full one, and for a deoptimization investigation you usually want the deopts and the ICs and nothing else.
The V8 flags differ by Node version, and the README documents two of them
You can also pass the requisite command line options directly to the node process, and the README gives the sets for two eras of Node.
For NodeJS 16 and later the flags are these.
node \
--prof \
--log-deopt \
--log-ic \
--log-maps \
--log-maps-details \
--log-internal-timer-events \
--log-code \
--log-source-code \
--detailed-line-info \
path/to/file.jsFor NodeJS 12.x and 14.x the IC and map flags have different names, using trace instead of log.
node \
--prof \
--trace-ic \
--trace-maps \
--trace-maps-details \
--log-internal-timer-events \
--log-code \
--log-source-code \
--detailed-line-info \
path/to/file.jsThe README is explicit about why this is a moving target, saying that since V8 is constantly evolving, the exact command line switches depend on the version of V8, NodeJS and so on. Running with the requisite switches creates an isolate-<id>-v8.log file in the current directory that the extension can consume.
The README then explains what each option buys, and it is worth reading because it maps directly onto the views. --prof writes statistical profiling information, and implies --log-code. --log-deopt writes the deoptimization events the extension uses to track and explain deoptimizations. --log-ic and --trace-ic write inline cache state transitions, which is how you see a function transition from monomorphic to polymorphic because of differing inputs. --log-maps and --trace-maps write the internal representation of a JavaScript object's structure and properties, used to isolate differences in object shape that might cause inline cache misses and trigger recompilation, and --log-maps-details adds further detail on top of that.
The licence files in the tree tell you where the code came from
The repository root contains a set of licence files that is unusual for an extension of this size, and it is the clearest statement of what the code is made of.
There is a LICENSE, a LICENSE.chromium, a LICENSE.deoptigate, a LICENSE.v8, a LICENSE.vscode, plus a THIRD_PARTY_NOTICES file. The package.json import map makes the same point in code, with entries mapping #v8/*.js, #vscode/*.js, #chromium/*.js and #deoptigate/*.js onto directories under src/third-party-derived/. The core and extension code live under src/core and src/extension, and there is a #benchmarks entry pointing at src/test/benchmarks.ts.
So the extension is a Microsoft authored shell around code derived from three other projects: V8 itself, the Chromium DevTools front end, and deoptigate, an existing deoptimization viewing tool. The upstream V8 project is what defines the log format, and the DevTools code is what provides the profiling tree view.
The package itself is MIT licensed, and the extension's own licence file covers the parts Microsoft wrote. The derived directories carry their own licences, and the presence of THIRD_PARTY_NOTICES alongside them is the mechanism by which the attribution obligations of Chromium, V8 and deoptigate are met.
For a user this matters less than for someone vendoring the code, but it does explain why the tree is shaped the way it is: the log parsing and the visualisations come from upstream projects that already know the format.
Untrusted workspaces get a deliberately reduced feature set
The package manifest declares a capability for untrusted workspaces, and the description is unusually specific.
The untrustedWorkspaces support is set to limited, and the description explains why: the extension will not attempt to use an executable, that is dumpbin or nm, to resolve native function symbols.
That is a security decision with a visible cost. Resolving native function symbols in a V8 log means shelling out to a platform tool, dumpbin on Windows and nm elsewhere, and running an external binary against a file that came from the workspace you just opened. In a folder you do not trust, that is a vector. In a folder you do trust, you get symbol names on native frames in the profile view.
So the extension asks for trust before it runs those tools, which is the behaviour VS Code's untrusted workspace support is designed for, and a workspace that has not been marked trusted keeps the extension running with the symbol resolution switched off.
The activation events are worth noting too, because they show how the extension attaches itself to a workspace. It activates on a custom language id, deoptexplorer-v8-map, on its own commands, on several of its own views, when the workspace contains a file whose name ends in -v8.log, and on three webview panels. That last point is the practical takeaway for a user: dropping a log file into the project is enough to bring the extension up, so the tree view appears as soon as a log exists.
Where this tool stops, and what to reach for instead
Three limits are visible in the documentation.
The first is the audience. The tool is for advanced users with an understanding of V8's internals, and it deliberately gives no recommendations. If the question is why the service got slower after a deploy, a profiler with a sampling view and a flame graph will get you an answer faster, because it asks you to know far less. Deopt Explorer is for the second question, the one that starts after the profile has already pointed at a function.
The second is the flag drift. The switches differ between Node 12 and 14 and Node 16 and later, and the README says plainly that because V8 is constantly evolving, the exact switches depend on the version you are running. A flag renamed in a newer V8 turns the whole exercise into a guessing game, and dexnode exists precisely because maintaining that mapping by hand is painful.
The third is the age of the releases. The published versions are from May 2023, and while the repository has seen commits as recently as 2026-10-02, the extension you can install from the marketplace is built from code whose last release was three years ago, and V8 has changed a great deal in that time. A log format change in a newer V8 could leave the extension unable to read the log at all, which is why running a current Node and checking that the views populate is the first thing to verify rather than the last.
Within its niche, though, the combination of a purpose built log producer and a purpose built log viewer is the reason to use this rather than a general purpose tool.
Editorial conclusion
deoptexplorer-vscode fits a performance engineer chasing a JavaScript regression that only shows up after the optimizing compiler gives up, since the deoptimization and inline cache views explain why a function keeps falling back to the interpreter, and the map view shows which property assignment created a shape change. It is the wrong tool for a developer who wants recommendations, since the README says explicitly that it does not provide them, and the wrong tool on a runtime whose flags differ from the ones documented. Before adopting it, install dexnode with npm install --global dexnode, generate a log with dexnode against your own script, and check which V8 flags your Node version actually accepts, because the switch names changed between the 12.x, 14.x and 16+ command lines.
Frequently asked questions
What does deoptexplorer-vscode show me?
It reads a V8 trace log and provides views of CPU profiles, inline cache evolution, deoptimizations, function state and V8 maps, including a tree to trace each property in a map back to the function that assigned it. The README says it is aimed at advanced users and does not provide recommendations for performance improvements.
How do I generate a V8 log for deoptexplorer-vscode?
Install dexnode with npm install --global dexnode and run your script through it, for example dexnode myscript.js, or use npm exec dexnode myscript.js, or deno run -A npm:dexnode myscript.js for Deno. The log is written by default to a file named isolate-<pid>-<isolate id>-v8.log.
Which node flags do I need for a V8 log?
On NodeJS 16 and later the README lists --prof, --log-deopt, --log-ic, --log-maps, --log-maps-details, --log-internal-timer-events, --log-code, --log-source-code and --detailed-line-info, while on NodeJS 12.x and 14.x the IC and map switches are --trace-ic, --trace-maps and --trace-maps-details.
What can I leave out of the V8 log?
The dexnode options let you exclude maps, inline caches, deoptimizations, the CPU profile and sources individually with --no-maps, --no-ics, --no-deopts, --no-profile and --no-sources, each of which is included by default.
What does deoptexplorer-vscode do in an untrusted workspace?
The package manifest marks untrusted workspace support as limited, with the description explaining that the extension will not attempt to use an executable such as dumpbin or nm to resolve native function symbols. The rest of the extension still runs.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/microsoft-deoptexplorer-vscode)Was this useful?