> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# rules_js 3.0 - out with the old (and default to the new)

> What’s new in rules_js 3.0: default MODULE.bazel, removed old APIs and pnpm 8, and improved maintainability and correctness. Ideal upgrade path

export const BlogPost = ({title, date, authors, tags, image, children}) => {
  const tagList = tags ? tags.split(", ").filter(Boolean) : [];
  const tagSlug = t => t.toLowerCase().replace(/&/g, "").replace(/\+/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
  const formattedDate = date ? new Date(date + "T00:00:00").toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric"
  }) : "";
  return <section className="w-full flex justify-center px-4 py-12 md:py-16">
      <div style={{
    maxWidth: "800px",
    width: "100%"
  }}>
        {image && (typeof image === "string" ? <img noZoom src={image} alt={title} className="w-full rounded-xl mb-8" style={{
    maxHeight: "400px",
    objectFit: "cover"
  }} /> : <div className="blog-post-hero-image">{image}</div>)}
        <h1 className="text-3xl md:text-4xl font-bold text-zinc-900 dark:text-white">
          {title}
        </h1>
        <div className="flex flex-wrap items-center gap-3 mt-4 text-sm text-zinc-500 dark:text-zinc-400">
          {authors && <span>{authors}</span>}
          {authors && formattedDate && <span>·</span>}
          {formattedDate && <span>{formattedDate}</span>}
        </div>
        {tagList.length > 0 && <div className="flex flex-wrap gap-2 mt-3">
            {tagList.map(tag => <a key={tag} href={"/blog/tags/" + tagSlug(tag)} className="px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-blue-100 dark:hover:bg-blue-900/40 hover:text-blue-700 dark:hover:text-blue-300 transition">
                {tag}
              </a>)}
          </div>}
        <hr className="my-8 border-zinc-200 dark:border-zinc-700" />
        <div className="prose dark:prose-invert max-w-none">{children}</div>
      </div>
    </section>;
};

export const MarketingPage = () => <div className="marketing-page-marker" style={{
  display: "none"
}} />;

export const Section = ({children, className = "", gray = false, dark = false, id}) => <section id={id} className={`w-full flex justify-center px-4 py-16 md:py-24 ${gray ? "bg-gray-50 dark:bg-zinc-900" : dark ? "bg-zinc-900 dark:bg-zinc-950" : ""} ${className}`}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {children}
    </div>
  </section>;

<MarketingPage />

<BlogPost title="rules_js 3.0 - out with the old (and default to the new)" date="2026-02-09" authors="Jason Bedard" tags="JavaScript, Releases, Bazel">
  <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/blog/hashnode/hn-d01957e7c5.jpg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=1e8b1d03278fff6cbe78514090f0697a" alt="" className="blog-post-cover" width="1600" height="1067" data-path="images/blog/hashnode/hn-d01957e7c5.jpg" />

  `rules_js` 3.0 is now available. This release simplifies the internals by dropping support for older Bazel, pnpm, and Node versions while keeping the public `rules_js` APIs stable, prioritizing maintainability, performance, and correctness over new surface features.

  We've also launched new documentation with this release, at [https://aspect.build/docs/bazel/javascript](https://aspect.build/docs/bazel/javascript)

  If you're already on Bazel 7+, loading `rules_js` via `MODULE.bazel`, and using pnpm 9+, the upgrade should be straightforward.

  ## What’s Changed?

  * 🚫 Remove Bazel 6 support

  * 🚫 Remove pnpm 8 support

  * 🚫 Remove WORKSPACE support

  * 🧹 Remove some rarely used APIs

  * ✅ Enable enhancements that were previously opt-in

  ## Ecosystem Compatibility

  Related rulesets including `rules_ts`, `rules_swc`, `rules_jest`, and `rules_webpack` have been tested with `rules_js` 3.0 and are compatible with their current releases.

  The dependency on `aspect_bazel_lib` 2.x has been replaced with `bazel_lib` 3.0 ([2567](https://github.com/aspect-build/rules_js/pull/2567)). With this change, `rules_js` ensures any `aspect_bazel_lib` usage remains forward-compatible with `bazel_lib`, as long as your repository does not override the `aspect_bazel_lib` module.

  ***

  The most significant change is the removal of pnpm 8 and WORKSPACE support.

  Early versions of `rules_js` were designed around:

  * The pnpm lockfile format at the time

  * Limitations of Bazel repository rules in WORKSPACE mode

  To avoid diverging code paths:

  * When pnpm updated its lockfile format, `rules_js` downgraded it internally.

  * When Bazel MODULEs (bzlmod) were introduced, `rules_js` delegated much of the logic back to WORKSPACE-based implementations.

  That approach kept behavior consistent, but added complexity and limited adoption of newer pnpm and bzlmod features.

  With pnpm 8 and WORKSPACE removed:

  * The core architecture is simpler

  * Legacy compatibility layers are gone

  * A single modern code path replaces multiple branches

  * Bugs such as the pnpm lockfile being parsed twice under bzlmod ([2480](https://github.com/aspect-build/rules_js/pull/2480)) are eliminated

  ***

  ## Notable CHANGELOG

  **📦 Platform-specific optional npm dependencies (**[**2538**](https://github.com/aspect-build/rules_js/pull/2538)**)**

  That annoying `@esbuild/android-arm64` you always see being fetched and know you *really* don't need will no longer be fetched. Other common examples are platform specific `@swc/*`, `@rollup/*` or the upcoming `@typescript/native-preview-*` packages.

  **🔗** `proto_library` **support in JS deps (**[**2721**](https://github.com/aspect-build/rules_js/pull/2721)**)**

  Experimental support for directly depending on `proto_library` targets in `js_library(deps)` or `ts_project(deps)`. You register a `protoc` plugin toolchain for your choice of codegen tooling.

  **🗂 Package exclusion presets + default exclusion list (**[**2652**](https://github.com/aspect-build/rules_js/pull/2652)**)**

  That 10mb `CHANGELOG.md` you always notice? Gone!

  The `npm_exclude_package_contents` API now has multiple presets instead the previous single `use_defaults = True` which was opt-in. The previous `use_defaults = True` has been replaced with the `"yarn_autoclean"` preset which mimics the `yarn autoclean` command. A new `"basic"` preset is now available and enabled by default - this is less aggressive then the yarn list while still excluding common unnecessary files often shipped in npm packages.

  **⚡ Better Bazel 9 compatibility and performance**

  Bazel 9 has some new features such as the [facts API](https://bazel.build/rules/lib/builtins/module_ctx#facts) which will now be used to make things like pnpm downloads reproducible even if you don't manually provide SHAs ([2698](https://github.com/aspect-build/rules_js/pull/2698)).

  Path-mapping support has also been expanded ([2575](https://github.com/aspect-build/rules_js/pull/2575)).

  **🛣 Initial support for Bazel path mapping (**[**2575**](https://github.com/aspect-build/rules_js/pull/2575)**)**

  Bazel path mapping allows some actions to be cached and reused across compilation modes such as `dbg` and `release`.

  **🟢 Default Node version bumped to v22 (**[**2649**](https://github.com/aspect-build/rules_js/pull/2649)**)**

  Along with upgrading the minimum `rules_nodejs` version the default node version is now also updated to the LTS v22.

  ***

  ## What's Next

  `rules_js` 3.0 is launched and ready for you to upgrade. Check out the [updated docs](https://aspect.build/docs/bazel/javascript) or try a new project using the [https://github.com/aspect-starters/js](https://github.com/aspect-starters/js) repo which has all the latest versions.

  Having problems? Aspect offers a paid support plan with a dedicated Slack channel for your team under an SLA.
</BlogPost>
