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

# JavaScript and TypeScript

> Build JavaScript and TypeScript with Bazel using rules_js, rules_ts, pnpm workspaces, Jest, esbuild, webpack, and Next.js integrations.

export const gatedHref = (user, href, group) => {
  const loggedIn = !!(user && user.loggedIn);
  const groups = user && user.tenantMetadata && user.tenantMetadata.docsGroups || [];
  if (loggedIn && (!group || groups.indexOf(group) >= 0)) {
    return href;
  }
  return loggedIn ? undefined : "/login?redirect=" + encodeURIComponent(href);
};

Bazel gives JavaScript and TypeScript projects incremental builds with correct caching, including monorepos with hundreds of packages.

<Tip>
  Stuck?

  * Check for [known issues](https://github.com/aspect-build/rules_js/issues)
  * Ask in <code>#javascript</code> on [Bazel Slack](https://slack.bazel.build)
  * Sign up for [commercial support](/services), provided by Aspect as a shared Slack channel.
</Tip>

## Create a new project

<Steps>
  <Step title="Install the Aspect CLI">
    ```bash theme={null}
    brew install aspect-build/aspect/aspect
    ```

    For more details, see [Aspect CLI](/docs/cli).
  </Step>

  <Step title="Scaffold a new project">
    ```bash theme={null}
    aspect init my-app --preset js && cd my-app
    ```

    A working Bazel + JS/TS setup: pnpm workspaces, `rules_js`, `rules_ts`, and Gazelle-generated BUILD files. See [`aspect init`](/docs/cli/tasks/init) for the full flag reference (presets, `--template`, `--license`).

    Prefer GitHub's "Use this template" button? Start from [aspect-starters/js](https://github.com/aspect-starters/js) instead, or `git clone https://github.com/aspect-starters/js my-app`.
  </Step>
</Steps>

## Explore Bazel

<Columns cols={2}>
  <Card title="Starter template" icon="clone" href="https://github.com/aspect-starters/js">
    Clone the starter repository for a working Bazel + JS/TS setup.

    Open it in a GitHub Codespace to try it without a local install.
  </Card>

  <Card title="Bazel 105: JS and TS training" icon="graduation-cap" href="/learning/bazel-105">
    A hands-on course for building, testing, and shipping JS and TS with Bazel.

    Covers `pnpm`, TypeScript, `esbuild`, Vite, and more.
  </Card>
</Columns>

## Package management with pnpm

`rules_js` consumes a `pnpm-lock.yaml` lockfile to create a correct `node_modules` tree.
Unlike `npm` or `yarn` lockfiles, pnpm's lockfile format is expressive enough for Bazel to resolve the dependency graph without ever running a package manager itself.

`rules_js` can also provide the `pnpm` binary itself, so every developer on your team uses the same version.

Aspect recommends you migrate to `pnpm` *before* adopting Bazel.

Your `.npmrc` file should include:

```ini theme={null}
hoist=false
```

See the [pnpm guide](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md) for details.

<Tip>
  Remember to run <code>pnpm install</code> after changing <code>package.json</code>. Bazel reads directly from <code>pnpm-lock.yaml</code>, so lockfile changes won't be picked up until you update it.
</Tip>

### Automatically updating the lockfile

If you'd rather not run `pnpm install` manually, `rules_js` can update `pnpm-lock.yaml` for you. Set `update_pnpm_lock = true` in `npm_translate_lock` and Bazel runs `pnpm install` whenever its inputs change. You don't have to remember to update the lockfile and `rules_js` always uses the same version of `pnpm` from Bazel.

You can migrate from an existing `npm` or `yarn` lockfile if you haven't migrated to `pnpm` yet. Pass your `package-lock.json` or `yarn.lock` to `npm_translate_lock` with the `npm_package_lock` or `yarn_lock` attributes. When either is set, `update_pnpm_lock` defaults to `true` and `rules_js` automatically runs `pnpm import` to produce the `pnpm-lock.yaml` that Bazel needs.

When you enable `update_pnpm_lock`, you must list every `package.json` and any
other input files in the `data` attribute of `npm_translate_lock`. This tells
Bazel which files to watch so it knows when to re-run `pnpm`. In smaller projects, this list may be short and easy to maintain, but in larger monorepos, it's easy to forget to add a new file. When that happens, Bazel won't know to re-run `pnpm`, which can lead to hard-to-debug staleness issues.

See [pnpm and rules\_js](/docs/bazel/javascript/pnpm_rules_js#update_pnpm_lock) and the [`npm_translate_lock`](/docs/bazel/javascript/aspect_rules_js/npm_extensions#tag-npm_translate_lock) reference for full details.

**API reference:**
[npm extensions](/docs/bazel/javascript/aspect_rules_js/npm_extensions) |
[npm rules](/docs/bazel/javascript/aspect_rules_js/npm_defs)

**Troubleshooting:**
[rules\_js troubleshooting](https://github.com/aspect-build/rules_js/blob/main/docs/troubleshooting.md) |
[FAQ](https://github.com/aspect-build/rules_js/blob/main/docs/faq.md)

## Node.js programs

The `js_library`, `js_binary`, and `js_run_binary` rules let you build, test, and run JavaScript programs under Bazel.
Bazel provides a hermetic Node.js toolchain so builds aren't affected by whatever version of Node is on a developer's machine.

**API reference:**
[JavaScript rules](/docs/bazel/javascript/aspect_rules_js/js_defs)

## Editor support

Bazel links `node_modules` under `bazel-bin/[path/to/package]/node_modules`, not in your source tree. Your editor's TypeScript server, ESLint integration, and IntelliSense don't know about `bazel-bin`. They look for a `node_modules` directory next to the `package.json`.

Run `pnpm install` in your source tree so editor tooling can resolve packages and types:

```shell theme={null}
pnpm install
```

This `node_modules` is for editor use only. Bazel ignores it and reads dependencies directly from `pnpm-lock.yaml`. Re-run `pnpm install` whenever `package.json` changes so your editor stays in sync with what Bazel builds.

<Tip>
  Keep your <code>.npmrc</code> aligned with <code>rules\_js</code> by setting <code>hoist=false</code>. This makes the source-tree <code>node\_modules</code> match the layout Bazel produces, so import errors reproduce identically in and out of Bazel. See [pnpm and rules\_js](/docs/bazel/javascript/pnpm_rules_js).
</Tip>

For debugger setup (VS Code launch configs, Chrome DevTools), see [Debugging](/docs/bazel/javascript/rules_js#debugging) in the `rules_js` guide.

## Protocol Buffers and gRPC

`rules_js` includes experimental support for generating JavaScript and TypeScript code from `.proto` files which are referenced in `proto_library` targets.

1. Bring your own `protoc` plugin, such as [`@bufbuild/protoc-gen-es`](https://github.com/bufbuild/protobuf-es)
2. Configure it with a `js_proto_toolchain`
3. Reference `proto_library` targets anywhere a `js_library` can appear. Bazel invokes the code generator automatically.

**API reference:**
[Protocol Buffer rules](/docs/bazel/javascript/aspect_rules_js/js_proto)

## Frameworks and ecosystem

Bazel works with the JavaScript tools you already use. Available integrations include:

<Columns cols={2}>
  <Card title="Next.js" icon="browser" href="/docs/bazel/javascript/aspect_rules_js/contrib_nextjs_defs">
    Build and run Next.js apps under Bazel.
  </Card>

  <Card title="Protocol Buffers and gRPC" icon="message-arrow-up" href="/docs/bazel/javascript/aspect_rules_js/js_proto">
    Generate TypeScript clients from `.proto` files using Connect.
  </Card>
</Columns>

<Columns cols={2}>
  <Card title="Bundling" icon="box-archive" href="/docs/bazel/javascript/aspect_rules_js/js_defs#function-js_run_binary">
    Use esbuild or webpack with `js_run_binary` for production bundles.
  </Card>

  <Card title="Dev servers" icon="play" href={gatedHref(user, "/learning/bazel-105/hello-browser#run-the-app-with-bazel")}>
    Run Vite or other dev servers with live reloading under Bazel.
  </Card>
</Columns>

<Columns cols={2}>
  <Card title="Linting and formatting" icon="check" href={gatedHref(user, "/learning/bazel-105/format-and-lint")}>
    Integrate ESLint, Prettier, Biome, and other tools.
  </Card>

  <Card title="Container images" icon="docker" href="/docs/bazel/javascript/aspect_rules_js/js_defs#rule-js_image_layer">
    Package Node.js apps into OCI images with `js_image_layer` and [rules\_oci](https://github.com/bazel-contrib/rules_oci).
  </Card>
</Columns>

For more working examples, see the [Bazel examples](https://github.com/aspect-build/bazel-examples) repository.

## Community

**[Join the Aspect Community Slack](https://slack.aspect.build)**, Aspect's free community support. Ask in `#help` for general support. Join the discussion and see what others are building with the [Aspect CLI](/docs/cli/overview) and [Aspect Extension Language (AXL)](/docs/cli/axl) in the `#cli` and `#axl` channels.

For Bazel and the Bazel rulesets, [Bazel Slack](https://slack.bazel.build) is the best place for support and discussion. Ask about Aspect's [rules\_js](/docs/bazel/javascript) in `#javascript` and [rules\_py](/docs/bazel/python) in `#python`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.