Skip to content

build: delay-load unused Windows DLLs to improve startup time - #67098

Open
azchohfi wants to merge 1 commit into
nodejs:mainfrom
azchohfi:win-delay-load-dlls
Open

azchohfi wants to merge 1 commit into
nodejs:mainfrom
azchohfi:win-delay-load-dlls

Conversation

@azchohfi

Copy link
Copy Markdown

Summary

Delay-load seven Windows DLLs that are currently linked as regular imports, avoiding the cost of loading them during process startup unless they are actually needed.

This reduces startup time for some short-lived Node.js processes without changing when or how the underlying functionality is used.

Motivation

On Windows, DLLs listed in an executable's import table are loaded during process initialization even if the process never calls into them.

Node.js imports several DLLs that are rarely needed by short-lived processes, but their loading cost is paid on every invocation.

This is particularly relevant for workloads that frequently spawn Node.js processes, such as package managers, build tools, and AI coding agents.

Changes

  • Configure seven Windows DLLs (crypt32, dbghelp, iphlpapi, ole32, shell32, userenv and winmm) for delay-loading in the build configuration
  • The DLLs are loaded automatically on first use through the Windows delay-load mechanism, so this change preserves the existing behavior
  • No changes to JavaScript APIs or runtime functionality

Performance

Measured on Windows 11 (i9-14900K), same build with and without the change, 100 interleaved runs each:

Configuration node -e 0 node --version
Before 40.5 ms 22.4 ms
After 38.0 ms 19.7 ms

Approximately 2.6 ms faster startup (~6% for node -e 0). The number of DLLs loaded at startup goes from 35 to 26.

The improvement is most relevant to short-lived processes, where initialization represents a significant portion of total execution time.

Testing

About 1,400 Node.js tests (crypto, tls, https, net, dns, os, fs, child processes, workers, reports and others) produced the same results with and without the change.

Additional context

This change is independent of a complementary libuv change, libuv/libuv#5389, that starts the Windows console resize watcher only when it is needed. Once Node.js picks up that change, user32.dll can be added to this list as well, which saves about another 5-8 ms per process.

I used GitHub Copilot to help investigate and measure this change. I reviewed the change and verified the results myself.

node.exe imports crypt32, dbghelp, iphlpapi, ole32, shell32, userenv
and winmm, so every process loads them, and the DLLs they depend on,
at start-up. They are only needed by less common code paths such as
the system certificate store, network interface queries and
diagnostic reports.

Delay-load them so they are loaded on first use. On Windows 11 this
takes `node -e 0` from 35 to 26 loaded images and saves about 2.5 ms
per process.

Signed-off-by: Alexandre Zollinger Chohfi <alzollin@microsoft.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp

@nodejs-github-bot nodejs-github-bot added build Issues and PRs related to Node.js builds or CI infrastructure. needs-ci PRs that need a full CI run. labels Oct 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Issues and PRs related to Node.js builds or CI infrastructure. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants