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

# External dependencies

> Declare npm, PyPI, and Go module dependencies in your workspace; rbs resolves them hermetically, locks them in rbs.lock, and shares them across workspaces.

rbs resolves third-party packages itself — it talks to the npm registry and PyPI
directly, resolves version ranges and transitive dependencies, and downloads
everything into a shared store. **No `npm install`, `yarn`, or `pip install` in your
workflow**, and no per-project `node_modules` bloat: a package version is downloaded
once per user and shared by every workspace that needs it.

## Declaring dependencies

Dependencies are declared in `WORKSPACE.rbs`, then referenced from build targets like
any other dependency.

<Tabs>
  <Tab title="npm">
    ```python theme={null}
    load("@rbs//nodejs/toolchain.rbs", "nodejs_toolchain")
    load("@rbs//nodejs/dependencies.rbs", "nodejs_repository")

    nodejs_toolchain(name = "nodejs", version = "22.15.1")

    nodejs_repository(
        name = "express_repo",
        package = "express",
        version = "4.18.2",
    )

    nodejs_repository(
        name = "types_node_repo",
        package = "@types/node",   # scoped packages work as-is
        version = "20.10.0",
    )

    # Build-time tools run on the host — mark them with host = True
    nodejs_repository(
        name = "typescript_repo",
        package = "typescript",
        version = "5.3.3",
        host = True,
    )
    ```

    Then depend on them from `BUILD.rbs`:

    ```python theme={null}
    load("@rbs//nodejs/rules.rbs", "nodejs_binary")

    nodejs_binary(
        name = "server",
        srcs = ["server.js"],
        main = "server.js",
        deps = [":express_repo"],
    )
    ```

    Declaring many packages at once:

    ```python theme={null}
    load("@rbs//nodejs/dependencies.rbs", "nodejs_repositories")

    nodejs_repositories(
        name = "web_deps",
        packages = [
            "express:4.18.2",
            "cors:2.8.5",
            "helmet:7.1.0",
        ],
    )
    ```
  </Tab>

  <Tab title="pip">
    ```python theme={null}
    load("@rbs//python/toolchain.rbs", "python_toolchain")
    load("@rbs//python/dependencies.rbs", "py_repository")

    python_toolchain(name = "python3", version = "3.12")

    py_repository(
        name = "django_repo",
        package = "django",
        version = "5.0.1",
    )

    py_repository(
        name = "requests_repo",
        package = "requests",
        version = "2.32.4",
    )
    ```

    Then depend on them from `BUILD.rbs`:

    ```python theme={null}
    load("@rbs//python/rules.rbs", "py_binary")

    py_binary(
        name = "manage",
        srcs = ["manage.py"],
        main = "manage.py",
        deps = [":django_repo", ":requests_repo"],
    )
    ```

    `py_repositories(name, packages = ["django:5.0.1", ...])` declares a batch in one
    call.
  </Tab>

  <Tab title="Go modules">
    Go dependencies don't need workspace declarations — they come from the `go.mod` and
    `go.sum` you already commit:

    ```python theme={null}
    load("@rbs//go/rules.rbs", "go_binary")

    go_binary(
        name = "server",
        srcs = ["main.go", "go.mod", "go.sum"],
        deps = [":internal_lib"],
    )
    ```

    rbs fetches modules from the Go module proxy in a single, explicit staging step,
    **verifying every download against your committed `go.sum`** — then compiles fully
    offline, with module fetching disabled so nothing can be pulled mid-build. If
    `go.sum` is missing entries, the build fails and tells you to run `go mod tidy` and
    commit the result, rather than silently trusting whatever was fetched.

    A committed `vendor/` tree is also supported: when `vendor/` is present, rbs builds
    from it offline without touching the network at all.

    Downloaded modules land in a module cache shared by every target in the workspace,
    so each module version is fetched once per workspace, not once per target.
  </Tab>
</Tabs>

## The lockfile: `rbs.lock`

For npm and pip dependencies, rbs records every resolution — the exact version chosen
for each declared and transitive package, plus integrity checksums — in `rbs.lock` at
the workspace root.

* **Commit it.** With a lockfile present, resolution is instant (no registry
  round-trips for known packages) and reproducible: everyone on the branch gets the
  same dependency tree.
* rbs updates it automatically when you change declared versions; there's no separate
  "lock" command to run.

Go modules are locked by `go.mod`/`go.sum` as usual — `rbs.lock` covers the
registry-resolved ecosystems.

## Where packages live

Resolved packages are materialized per-workspace under
`.rbs/external-deps/<platform>/<ecosystem>/<package>/`, which is where build rules
and language servers find them. Behind that path sits a **user-global store**
(under `~/.cache/rbs`, following `RBS_CACHE_DIR`): each package version is stored
once per user, and workspace paths link into it. A second workspace declaring
`express@4.18.2` links the existing copy instead of re-downloading it.

The store is managed with the rest of the [shared cache](/build/caching):
`rbs cache stats` reports it under "External deps", and `rbs cache gc` ages out
packages no workspace has used recently — anything swept re-resolves automatically on
the next build or sync.

## Syncing for your editor: `rbs sync`

Language servers need dependencies on disk before they can offer autocomplete and
go-to-definition — but on a fresh clone, packages only appear as targets get built.
`rbs sync` resolves everything up front:

```bash theme={null}
# Sync every target in the workspace
rbs sync //...

# Sync one target, a package, or several targets
rbs sync //myapp:server
rbs sync //myapp:all
rbs sync //myapp:server //lib:utils

# See what would be fetched without downloading
rbs sync //... --dry-run

# Detailed progress
rbs sync //... --verbose
```

Sync walks the targets' dependency graphs, resolves every external dependency
through the same resolvers the build uses, and reports what was downloaded versus
already cached. After it finishes, your editor's LSP has the full dependency set for
accurate autocomplete and type checking.

<Tip>
  Run `rbs sync //...` right after cloning a branch — it warms the workspace for both
  your editor and your first build.
</Tip>
