npm package: @mgwilt/nx-uv
Description: Nx plugin for uv workflows in Nx monorepos
Latest version: 1.0.0

# @mgwilt/nx-uv

[Nx](https://nx.dev/) plugin for running [uv](https://docs.astral.sh/uv/) workflows in [Nx](https://nx.dev/) monorepos.

[![CI](https://github.com/mgwilt/nx-uv/actions/workflows/ci.yml/badge.svg)](https://github.com/mgwilt/nx-uv/actions/workflows/ci.yml)
[![Coverage lines](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mgwilt/nx-uv/badges/.github/badges/coverage-lines.json)](https://github.com/mgwilt/nx-uv/blob/badges/.github/badges/coverage-lines.json)
[![Coverage functions](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mgwilt/nx-uv/badges/.github/badges/coverage-functions.json)](https://github.com/mgwilt/nx-uv/blob/badges/.github/badges/coverage-functions.json)
[![Coverage statements](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mgwilt/nx-uv/badges/.github/badges/coverage-statements.json)](https://github.com/mgwilt/nx-uv/blob/badges/.github/badges/coverage-statements.json)
[![Coverage branches](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mgwilt/nx-uv/badges/.github/badges/coverage-branches.json)](https://github.com/mgwilt/nx-uv/blob/badges/.github/badges/coverage-branches.json)
[![Coverage floor](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/mgwilt/nx-uv/badges/.github/badges/coverage-floor.json)](https://github.com/mgwilt/nx-uv/blob/badges/.github/badges/coverage-floor.json)
[![npm release](https://img.shields.io/npm/v/%40mgwilt%2Fnx-uv/latest?label=npm%20release&cacheSeconds=300)](https://www.npmjs.com/package/@mgwilt/nx-uv?activeTab=versions)

## Why this plugin exists

Nx provides a consistent task graph, caching, and affected-based CI so large repos run faster and more predictably. A common operational gap is that Python workflows powered by [uv](https://docs.astral.sh/uv/) often stay in separate shell scripts and one-off CI jobs, so they miss the same build/test orchestration used by the rest of the monorepo.

`@mgwilt/nx-uv` bridges that gap by turning common `uv` workflows into Nx-native targets and adding inference/generators so teams can standardize command execution, reduce bespoke pipeline logic, and manage Python alongside other stacks in a single CI model instead of maintaining a parallel toolchain path.

## When to use this plugin

- Run [uv](https://docs.astral.sh/uv/) commands through [Nx](https://nx.dev/) targets instead of ad-hoc shell scripts.
- Infer useful [uv](https://docs.astral.sh/uv/) targets from existing `pyproject.toml` files.
- Scaffold [uv](https://docs.astral.sh/uv/)-ready [Python](https://www.python.org/) projects and workspace config.
- Keep [Python](https://www.python.org/) work in the same task graph, caching, and CI flow as the rest of your monorepo.

## Tools

- Executors for [uv](https://docs.astral.sh/uv/) command families:
  - `@mgwilt/nx-uv:project`
  - `@mgwilt/nx-uv:uv`
  - `@mgwilt/nx-uv:pip`
  - `@mgwilt/nx-uv:tool`
  - `@mgwilt/nx-uv:python`
  - `@mgwilt/nx-uv:auth`
  - `@mgwilt/nx-uv:cache`
  - `@mgwilt/nx-uv:self`
  - `@mgwilt/nx-uv:studio`
- Generators:
  - `@mgwilt/nx-uv:workspace`
  - `@mgwilt/nx-uv:project`
  - `@mgwilt/nx-uv:integration`
  - `@mgwilt/nx-uv:convert`
- [Nx](https://nx.dev/) plugin inference (`createNodesV2`) for `pyproject.toml`.

## Install

Prerequisites:

- [Nx](https://nx.dev/) workspace
- [uv](https://docs.astral.sh/uv/) installed and available on `PATH`

Install the plugin:

```bash
pnpm add -D @mgwilt/nx-uv
```

## Interactive studio (TUI)

Launch the interactive monorepo manager directly with `pnpm dlx` (recommended):

```bash
pnpm dlx -p @mgwilt/nx-uv nx-uv tui
```

Shorthand (when supported by your pnpm version/environment):

```bash
pnpm dlx @mgwilt/nx-uv tui
```

The studio provides:

- Workspace setup and inference configuration
- Python app/lib/script generation
- Integration template scaffolding
- Convert existing projects to nx-uv defaults
- Nx target execution across all projects
- Ad-hoc `uv` command execution
- Preview-before-apply flow for mutating actions

Optional flags:

- `--cwd=<path>` scan and manage a workspace from a specific directory
- `--readonly` disable mutation/apply operations
- `--initial-view=<dashboard|workspace|project|integration|convert|inference|tasks|uv>`

If plugin inference is configured with `includeGlobalTargets: true` and a root uv workspace exists, the root inferred project also gets a `<targetPrefix>tui` target (for example `uv:tui`).

## Brand new monorepo example

This walkthrough creates a new [Nx](https://nx.dev/) monorepo and uses this plugin to scaffold a working [uv](https://docs.astral.sh/uv/) + [Python](https://www.python.org/) example.

1. Create a new workspace:

```bash
pnpm create nx-workspace@latest acme-monorepo --preset=ts --packageManager=pnpm --nxCloud=skip --interactive=false
cd acme-monorepo
```

2. Install this plugin and initialize workspace-level [uv](https://docs.astral.sh/uv/) config:

```bash
pnpm add -D @mgwilt/nx-uv
pnpm nx g @mgwilt/nx-uv:workspace --name=acme --membersGlob='packages/py/*'
```

3. Generate a [Python](https://www.python.org/) app and scaffold integrations:

```bash
pnpm nx g @mgwilt/nx-uv:project api --projectType=app --directory=packages/py
pnpm nx g @mgwilt/nx-uv:integration --template=fastapi --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=github
```

Expected file tree (key files) after step 3:

```text
acme-monorepo/
├── nx.json
├── package.json
├── pyproject.toml
├── .github/
│   └── workflows/
│       └── uv-ci.yml
└── packages/
    └── py/
        └── api/
            ├── README.md
            ├── pyproject.toml
            ├── main.py
            ├── Dockerfile.fastapi
            ├── src/
            │   └── api/
            │       ├── __init__.py
            │       └── main.py
            └── tests/
                └── test_smoke.py
```

4. Add runtime and dev dependencies with [uv](https://docs.astral.sh/uv/):

```bash
cd packages/py/api
uv add fastapi uvicorn
uv add --dev pytest ruff
cd ../../..
```

5. Run plugin-backed targets via [Nx](https://nx.dev/):

```bash
pnpm nx run api:sync
pnpm nx run api:uv
pnpm nx run api:run
pnpm nx run api:test
pnpm nx run api:build
```

At this point you have a working monorepo with:

- Root `pyproject.toml` and [uv](https://docs.astral.sh/uv/) workspace members
- A generated `api` [Python](https://www.python.org/) project under `packages/py/api`
- Generated [FastAPI](https://fastapi.tiangolo.com/) starter files and a [GitHub Actions](https://github.com/features/actions) Nx-first CI template (`test`, `lint`, `typecheck`, `build`)
- [Nx](https://nx.dev/) targets that run uv commands consistently in CI/local dev

## Quick start (existing workspace)

1. Add the plugin to `nx.json`:

```json
{
  "plugins": [
    {
      "plugin": "@mgwilt/nx-uv",
      "options": {
        "targetPrefix": "uv:",
        "inferencePreset": "standard",
        "includeGlobalTargets": false
      }
    }
  ]
}
```

2. (Optional, recommended for new repos) Initialize [uv](https://docs.astral.sh/uv/) workspace config:

```bash
pnpm nx g @mgwilt/nx-uv:workspace --name=acme
```

3. Generate a [Python](https://www.python.org/) project wired for [uv](https://docs.astral.sh/uv/) + [Nx](https://nx.dev/):

```bash
pnpm nx g @mgwilt/nx-uv:project services/api --projectType=app
```

4. Run [uv](https://docs.astral.sh/uv/)-backed targets:

```bash
pnpm nx run api:sync
pnpm nx run api:test
pnpm nx run api:build
```

## Existing [Python](https://www.python.org/) projects

If your repo already has `pyproject.toml` files, the plugin can infer targets (for example `uv:sync`, `uv:run`, `uv:test`) based on your configured `targetPrefix` and inference preset.

### Customizing inferred targets

You can disable or override inferred targets in plugin options:

```json
{
  "plugins": [
    {
      "plugin": "@mgwilt/nx-uv",
      "options": {
        "targetPrefix": "uv:",
        "inferencePreset": "standard",
        "inferredTargets": {
          "test": false,
          "lint": {
            "command": "run",
            "commandArgs": ["--", "ruff", "check", "src"]
          }
        }
      }
    }
  ]
}
```

Supported inferred target keys are: `sync`, `run`, `lock`, `test`, `lint`, `build`, `tree`, `export`, `format`, `venv`, `publish`.

## Integration templates

Use integration templates to scaffold common [uv](https://docs.astral.sh/uv/) ecosystem files for CI, containers, dependency automation, and notebook workflows.

### How file output location works

- `--project=<name>` sets `<baseDir>` to that [Nx](https://nx.dev/) project's root.
- `--directory=<path>` sets `<baseDir>` to that directory relative to workspace root.
- If neither is set, `<baseDir>` defaults to workspace root (`.`).
- Workspace-level templates always write to repo root, even if `--project` or `--directory` is provided.
- Workspace-level templates are:
  - `github`
  - `gitlab`
  - `dependency-bots`
  - `pre-commit`

### Template matrix

| Template              | Scope          | Files generated                                     | Best for                                                                                                                                                   |
| --------------------- | -------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `alternative-indexes` | `baseDir`      | `<baseDir>/uv.indexes.toml.snippet`                 | Defining custom/internal [Python](https://www.python.org/) indexes                                                                                         |
| `aws-lambda`          | `baseDir`      | `<baseDir>/Dockerfile.lambda`                       | Packaging [uv](https://docs.astral.sh/uv/)-based [AWS Lambda](https://aws.amazon.com/lambda/) workloads                                                    |
| `coiled`              | `baseDir`      | `<baseDir>/scripts/coiled-example.py`               | Starting distributed [Python](https://www.python.org/) experiments with [Coiled](https://coiled.io/)                                                       |
| `dependency-bots`     | workspace root | `renovate.json`, `.github/dependabot.yml`           | Automated dependency update workflows with [Renovate](https://docs.renovatebot.com/) and [Dependabot](https://docs.github.com/en/code-security/dependabot) |
| `docker`              | `baseDir`      | `<baseDir>/Dockerfile`                              | Containerizing a [uv](https://docs.astral.sh/uv/) project with [Docker](https://www.docker.com/)                                                           |
| `fastapi`             | `baseDir`      | `<baseDir>/main.py`, `<baseDir>/Dockerfile.fastapi` | Bootstrapping a [FastAPI](https://fastapi.tiangolo.com/) service with [uv](https://docs.astral.sh/uv/)                                                     |
| `github`              | workspace root | `.github/workflows/uv-ci.yml`                       | [GitHub Actions](https://github.com/features/actions) Nx-first CI starter using `nx affected`                                                              |
| `gitlab`              | workspace root | `.gitlab-ci.uv.yml`                                 | [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) Nx-first CI starter using `nx run-many`                                                                     |
| `jupyter`             | `baseDir`      | `<baseDir>/scripts/setup-jupyter-kernel.sh`         | Registering a [uv](https://docs.astral.sh/uv/)-managed [Jupyter](https://jupyter.org/) kernel                                                              |
| `marimo`              | `baseDir`      | `<baseDir>/notebooks/example.marimo.py`             | Starting [marimo](https://marimo.io/) notebook workflows                                                                                                   |
| `pre-commit`          | workspace root | `.pre-commit-config.yaml`                           | Local code quality hooks for [uv](https://docs.astral.sh/uv/) projects using [pre-commit](https://pre-commit.com/)                                         |
| `pytorch`             | `baseDir`      | `<baseDir>/uv.pytorch.toml.snippet`                 | Configuring [PyTorch](https://pytorch.org/) index/source snippets                                                                                          |

### Command examples for all templates

```bash
pnpm nx g @mgwilt/nx-uv:integration --template=alternative-indexes --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=aws-lambda --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=coiled --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=dependency-bots
pnpm nx g @mgwilt/nx-uv:integration --template=docker --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=fastapi --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=github
pnpm nx g @mgwilt/nx-uv:integration --template=gitlab
pnpm nx g @mgwilt/nx-uv:integration --template=jupyter --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=marimo --project=api
pnpm nx g @mgwilt/nx-uv:integration --template=pre-commit
pnpm nx g @mgwilt/nx-uv:integration --template=pytorch --project=api
```

### Common options

- `--overwrite=true` replaces existing files instead of skipping them.
- `--directory=<path>` writes baseDir-aware templates into a non-project directory.
- `--skipFormat=true` skips formatter execution after generation.
- Prefer `--project` for app/lib scaffolds and no location flag for workspace-level templates.

### Notes and pitfalls

- Templates are starter scaffolds; you should review and harden generated files for production use.
- Running the same template multiple times without `--overwrite=true` leaves existing files unchanged.
- Workspace-level templates are intentionally global and may affect repository-wide automation.

## Compatibility and versioning

- Runtime [uv](https://docs.astral.sh/uv/) compatibility checks verify that `uv` is available and executable.
- `uv 0.9.x` and `0.10.x` are currently the tested ranges. Other versions log a warning and continue.

## Troubleshooting

### Nx plugin bootstrap failures

If `quality:ci` fails before running tasks with worker/bootstrap errors (for example `Failed to load ... Nx plugin(s)`), run:

```bash
pnpm quality:bootstrap
pnpm nx reset
pnpm quality:ci
```

If bootstrap still fails, run direct checks to isolate whether the issue is Nx plugin startup or project logic:

```bash
pnpm quality:fallback
pnpm --version
pnpm nx --version
node -v
```

### E2E execution permissions

The e2e suite executes a temporary shim binary from the local filesystem. In restricted environments (for example `noexec` mounts or sandboxed process policies), e2e tests may be skipped when executable spawning is not permitted.

In CI, an all-skipped e2e run is treated as a failure by default. Set `NX_UV_ALLOW_E2E_ALL_SKIPPED=1` only in known restricted CI environments where executable shim spawning is intentionally blocked.

## LLM context files

This repository publishes LLM-friendly docs artifacts:

- `llms.txt`: concise index of high-signal project docs.
- `llms-full.txt`: expanded inline content for the same curated sources.

Regenerate and validate them with:

```bash
pnpm llms:generate
pnpm llms:check
```

## Additional docs

- [Documentation index](docs/index.md)
- [Maintainer guide (quality gates, CI, release)](docs/maintainers.md)
- [Maintainer toolchain matrix](docs/toolchain-matrix.md)
- [Runbook: gate failed before tasks started](docs/runbooks/gate-bootstrap-failure.md)
- [Sample scaffolding patterns](samples/README.md)