CODE VERIFIED

Node.js 27 Alpha Moves Glob Traversal Into Native C++

Node.js 27 alpha adds a native C++ glob engine. Inspect the wrapper boundary, async walker, permission test, and limits of the available performance evidence.

Nov 9, 2026, 6:50 pm PST · 6 min read
Conceptual illustration of an interface connected to a native engine traversing a branching directory tree.

Quick Answer

Node.js v27.0.0-alpha.0.0.0 moves its filesystem glob traversal and pattern engine into native C++ code. The October 29, 2026 official pre-release lists commit a8f2bf007e, “fs: implement glob natively,” as a semver-major change. This is evidence about an alpha build, rather than a stable or LTS release.

The familiar JavaScript entry points remain: fs.glob, fs.globSync, and fsPromises.glob. Their existence is not the news; the v26.13.0 documentation already describes them. The change is where the traversal and matching work happens. JavaScript still handles validation and adaptation around the native engine, including result conversion and application-supplied exclude callbacks.

In Plain English

A glob takes a pattern and finds matching filesystem entries. A developer sees paths or directory-entry objects; underneath, the runtime must interpret the pattern, visit directories, decide which entries match, and return results through the chosen synchronous or asynchronous API. This alpha puts the central traversal and pattern machinery in Node’s C++ subsystem.

That distinction matters when reading a “native glob” announcement. It describes the implementation boundary, not the disappearance of JavaScript from the operation. Calling a JavaScript API can still involve a native walker, and calling an application callback still requires returning to JavaScript. Keeping those two facts together makes the source easier to understand and avoids promising an execution model the code does not provide.

The official release labels this semver-major. Developers evaluating the alpha should therefore treat the familiar API names as a starting point for compatibility testing, rather than proof that every observable behavior is unchanged. The tagged documentation remains the reference for supported options and pattern rules.

Code Evidence

The JavaScript wrapper selects a native binding

In the tagged JavaScript wrapper, the module imports internalBinding('glob'). The synchronous method delegates to globBinding.globSync(...). The asynchronous paths use globBinding.globStart(...), and the async generator obtains batches with handle.next() before yielding paths or Dirent objects. These are concrete routing points showing that the public-facing wrapper now hands the walk to a separate binding.

The wrapper still has a job. It validates and adapts options and constructs the JavaScript result representation. A claim that globbing is now entirely JavaScript-free would erase this layer and misdescribe the tagged implementation. The source supports a narrower, more useful statement: the wrapper delegates its traversal and matching work to the native glob subsystem.

C++ owns the walk and asynchronous slices

The native binding parses walk arguments and patterns. Its synchronous route calls glob::GlobSync(...). For asynchronous work, GlobRequest::DoThreadPoolWork() calls walk_.RunSlice(..., false, ...), while the request exposes operations named next, all, and cancel.

The walker source implements Walk::RunSlice() and the synchronous GlobSync() loop. The release commit also adds parser, matcher, Unicode-handling, and abstract-syntax-tree code under src/glob/. Together, the wrapper’s delegation and these C++ implementation points establish the architectural change more clearly than the word “native” alone.

Exclude callbacks cross the boundary

The binding retains a JavaScript exclude filter. Asynchronous worker slices can pause to collect questions; AnswerQuestions() calls the filter before the walk resumes. An application-provided callback consequently remains part of JavaScript execution even though the traversal engine is native. This is a relevant boundary for anyone comparing an option-only glob with one that calls custom exclusion logic.

The documentation describes options including maxDepth, followSymlinks, and withFileTypes, alongside wildcards, globstar, extglobs, braces, dotfiles, and platform case sensitivity. These details belong in an application’s evaluation because they describe actual matching requirements. The v26.13.0 API documentation already exposes the glob APIs and options, supporting the interpretation that this story concerns an implementation rewrite rather than an invented API surface.

A permission regression test has a precise scope

The release commit includes a permission-subtree regression test. It runs with the permission model and filesystem read access limited to a subtree. The assertions check that a glob starting from the unauthorized parent returns no entries and emits denied-path diagnostics, while a glob whose working directory is inside the permitted subtree returns the expected files.

This documents a specific intended boundary: permission to read a subtree does not make its parent a permitted starting point for this test. It does not prove every traversal, symlink, or permission combination safe. The research inspected the test source; it did not execute the test.

Conceptual illustration of a software interface connected to a branching filesystem layer.
AI-generated conceptual illustration of the interface and native traversal boundary; not a screenshot or literal technical diagram.

Why It Matters

For developers following runtime internals, this is a concrete example of moving a filesystem operation below the JavaScript layer while preserving a JavaScript-facing interface. Pattern parsing, matching, and traversal now have a native implementation to inspect, but callbacks and result adaptation still connect that engine to application code. That separation is the central technical finding.

Our editorial inference is that evaluating the change should focus on the patterns and options an application actually uses. A tool that depends on directory-entry results, exclusions, or symlink behavior has more to check than whether a simple wildcard returns a file. The semver-major release designation reinforces the need to verify relevant behavior rather than infer compatibility from unchanged entry-point names.

Performance remains a separate question. The PR discussion contains early benchmark claims and reviewer feedback that asynchronous globbing remained slower than node-glob in the reviewer’s comparison. This article reports no independent benchmark and makes no universal speed claim. A native implementation is an architectural fact; a workload’s speedup requires measurements for that workload.

An Open Question

How will the alpha’s native walker compare on real application patterns that combine asynchronous iteration, custom exclusions, and permission restrictions?

Resolving that question would require reproducible workload definitions, matching correctness checks, and measurements against a clearly identified baseline. It would also require reporting the runtime version, platform, options, and callback behavior so a result could be interpreted. The inspected release and code establish the implementation boundary; they do not supply that independent evaluation.

Scope and Limitations

This article is based on the supplied official-source research for v27.0.0-alpha.0.0.0. No local runtime test, cross-platform compatibility matrix, or benchmark was executed. The permission test is discussed as source evidence, not as a newly observed passing run. The release’s alpha status and semver-major classification should remain visible when using this article to plan an evaluation.

The release lists commit a8f2bf007e, and the tagged source contains the native implementation. PR #65392 currently reports a closed, rather than merged, status in the research. We therefore do not describe that PR as merged. The supported release fact is the commit’s inclusion in the official alpha release and the implementation visible at that tag.

Sources