Skip to content

Generating Compile Cache Ahead of Runtime #58482

Description

@beeequeue

What is the problem this feature will solve?

It is currently not possible to generate the compile cache without executing the files that will be cached.

Currently, container images and lambda functions can't easily generate code caches ahead of the actual runtime, since the code may have effects you may not want to execute early.

What is the feature you are proposing to solve the problem?

Would it be possible to add a way to generate the compile cache without executing the relevant files, i.e. walking the module tree from the entry point, generating caches along the way?

Perhaps something like node --generate-compile-cache path/to/entrypoint.mjs
and/or

module.generateCompileCache("path/to/entrypoint.mjs")

What alternatives have you considered?

You may be able to work around this by adding "dry-run" code paths specifically for code cache generation, but this is a hacky workaround that can require massive effort.

Activity

  1. joyeecheung commented on May 29, 2025

    @joyeecheung
    Member

    I think theoretically yes, but in practice it is more subtle:

    1. Static analysis only goes so far for statically imported ESM - if there's any CJS in the graph (even if it's imported) their dependencies would be excluded because require() is not very reliable for walking. If there's any dynamic import() in the graph with dynamic module request it would also not be reliable. Considering how common it is for CJS to show up in the wild in dependencies it might result in a lot of cache miss in the real world.
    2. If there's any loader hooks used to mutate resolution the walk again would be unreliable without executing the hooks.

    That is technically a bundler problem and different bundlers can have different behaviors, with varying degree of accuracy. The accuracy of the graph would only be a best effort if it's implemented by Node.js alone without actually executing the code. It would probably be more effective for Node.js to just provide an interface that just takes a list of files and their formats to generate the cache from, and leave the walking and the generation of that list to a third party, so that users can edit the list to make up for any misses or they can use more advanced tools to generate more accurate graphs.

    There are already some pretty good existing tools in the wild that should be able to generate this list e.g. madge, dependency-cruiser, and there might be more in the future, there's no need to re-invent a non-perfect wheel in core that might not necessarily be as good as new tools that might show up in the future.

  2. bnoordhuis commented on May 29, 2025

    @bnoordhuis
    Member

    Joyee says it more eloquently but I can perhaps phrase it more succinctly: too fragile to be viable.

  3. beeequeue commented on Jun 3, 2025

    @beeequeue
    ContributorAuthor

    So what if we skip walking the module tree path and only consider receiving a list of paths to generate a cache for, would that be achievable?

  4. bnoordhuis commented on Jun 3, 2025

    @bnoordhuis
    Member

    Possible, yes, but it seems kind of pointless. It'd be useless for the average node app.

    Depending on what you want to do, you can maybe already achieve it through the vm module's produceCachedData option.

  5. joyeecheung commented on Jun 18, 2025

    @joyeecheung
    Member

    I think a list-based approach is still practical and wouldn't be too difficult to implement. So instead of the proposal in OP, an alternative workflow (using https://github.com/sverweij/dependency-cruiser, which provides a lot of powerful options, and this is using the most basic ones) can be

    npx depcruise --output-type json --no-config ./entrypoint.js | jq '[.modules[].source] | unique' > deps.json
    NODE_COMPILE_CACHE=/path/to/cache/dir node --generate-compile-cache deps.json
    NODE_COMPILE_CACHE=/path/to/cache/dir node entrypoint.js
    

    Using the vm module doesn't exactly provide the same thing (e.g. cache miss handling and a directory structure that is compatible with the built-in compile cache)

  6. beeequeue commented on Jun 18, 2025

    @beeequeue
    ContributorAuthor

    I would be open to writing a simple CLI npm package to generate a list for this if needed :)

    Should I update the OP to this new approach, or just add a link to the new comment?

  7. joyeecheung commented on Jun 18, 2025

    @joyeecheung
    Member

    Updating the OP or adding a link SGTM.

    I think this may also work nicely with #58755 so that the bundle would be portable.

  8. joyeecheung commented on Jun 18, 2025

    @joyeecheung
    Member

    Actually now I realize that the list needs more than just the paths, it also needs the module type e.g. CommonJS/ESM/TypeScript. It may also be better paired with #55756 if support for TypeScript is needed.

  9. sharmaharisam commented on Sep 12, 2025

    @sharmaharisam

    Hey,
    Do we have any update for the list based AOT Caching approach?

  10. joyeecheung commented on Sep 19, 2025

    @joyeecheung
    Member

    I have a WIP here which currently works like this:

    # Put the list of files + their format and the files into a workspace
    $ mkdir workspace
    $ cd workspace
    $ echo "console.log('hello')" > hello.js
    $ echo '[{ "source": "hello.js", "format": "commonjs" }]' > list.json
    
    # Build the compile cache in that workspace, using environment variables to specify cache directory (relative) and portability
    $ NODE_COMPILE_CACHE=.compile_cache NODE_COMPILE_CACHE_PORTABLE=1 NODE_DEBUG_NATIVE=compile_cache node --compile-cache-for list.js
    
    # Move the workspace to a different place for deployment
    $ cd ../
    $ mv workspace deploy
    
    # Run the entry point from the deployment directory
    $ cd deploy
    $ NODE_COMPILE_CACHE=.compile_cache NODE_COMPILE_CACHE_PORTABLE=1 NODE_DEBUG_NATIVE=compile_cache node hello.js

    I think it's possible to add a JS API for this too, though that would take a bit more work than just a command line option for a dedicated Node.js process to do this because we'd want a separate cache handler for that API (e.g. you probably don't want to mix the compile cache of the cache building script itself and its dependencies with the compile cache of the application).

  11. joyeecheung commented on Sep 19, 2025

    @joyeecheung
    Member

    I was in a meeting that touched on this topic and someone (I forgot who, sorry!) suggested that it would be nice it we can ship it in the Node.js distribution for the version of npm bundled, so that after people installed Node.js and run the npm bundled with it, it can just pick that up. I'll think about how to design it in a way to make that possible.

  12. wraithgar commented on Sep 19, 2025

    @wraithgar
    Contributor

    I would be open to writing a simple CLI npm package to generate a list for this if needed :)

    I'm not 100% sure what all the constraints are, but if the question is "what dependencies does my package have and where are they?" then this is what npm query was designed to solve. Namely "how do I discover and list things in my dependencies based on common criteria?"

    ~/.n/v/n/v/l/n/npm (master|✔) $ cd (npm prefix -g)/lib/node_modules/npm
    ~/.n/v/n/v/l/n/npm (master|✔) $ npm query ':root *'|jq '.[] | "name:\(.name), path=\(.location)"'|head -20
    "name:@isaacs/cliui, path=node_modules/@isaacs/cliui"
    "name:ansi-regex, path=node_modules/@isaacs/cliui/node_modules/ansi-regex"
    "name:emoji-regex, path=node_modules/@isaacs/cliui/node_modules/emoji-regex"
    "name:string-width, path=node_modules/@isaacs/cliui/node_modules/string-width"
    "name:strip-ansi, path=node_modules/@isaacs/cliui/node_modules/strip-ansi"
    "name:@isaacs/fs-minipass, path=node_modules/@isaacs/fs-minipass"
    "name:@isaacs/string-locale-compare, path=node_modules/@isaacs/string-locale-compare"
    "name:@npmcli/agent, path=node_modules/@npmcli/agent"
    "name:@npmcli/arborist, path=node_modules/@npmcli/arborist"
    "name:@npmcli/config, path=node_modules/@npmcli/config"
    "name:@npmcli/fs, path=node_modules/@npmcli/fs"
    "name:@npmcli/git, path=node_modules/@npmcli/git"
    "name:@npmcli/installed-package-contents, path=node_modules/@npmcli/installed-package-contents"
    "name:@npmcli/map-workspaces, path=node_modules/@npmcli/map-workspaces"
    "name:@npmcli/metavuln-calculator, path=node_modules/@npmcli/metavuln-calculator"
    "name:@npmcli/name-from-folder, path=node_modules/@npmcli/name-from-folder"
    "name:@npmcli/node-gyp, path=node_modules/@npmcli/node-gyp"
    "name:@npmcli/package-json, path=node_modules/@npmcli/package-json"
    "name:@npmcli/promise-spawn, path=node_modules/@npmcli/promise-spawn"
    "name:@npmcli/query, path=node_modules/@npmcli/query"
  13. github-actions commented on Mar 19, 2026

    @github-actions
    Contributor

    There has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the never-stale Issues and PRs exempt from automated stale handling. label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment.
    For more information on how the project manages feature requests, please consult the feature request management document.

  14. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Mar 19, 2026
  15. beeequeue commented on Mar 19, 2026

    @beeequeue
    ContributorAuthor

    Pls no stale Mr GitHub bot :(

  16. removed
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Mar 20, 2026
  17. joyeecheung commented on Jun 14, 2026

    @joyeecheung
    Member

    I'm not 100% sure what all the constraints are, but if the question is "what dependencies does my package have and where are they?"

    Sorry, I missed this reply, I think the question is more that - since:

    1. Node.js distributes npm CLI
    2. The version of Node.js used to run this bundled npm CLI is already known in the distribution
    3. Can we pre-compile the cache and put them in the bundle, so after people installed a distribution of Node.js, the first npm something will already pick up the precompiled cache compiled suing that version of Node.js
  18. github-actions commented on Sep 13, 2026

    @github-actions
    Contributor

    This issue has been marked as stale due to 90 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  19. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues requesting new Node.js features.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions