Skip to content

Negated outputs patterns do not prevent caching of excluded directories #35150

@alissa9090

Description

@alissa9090

Current Behavior

When using negated patterns in outputs to exclude a subdirectory from caching, the excluded directory is still stored in the Nx cache.

Example project.json:

{
  "build": {
    "executor": "@nx/next:build",
    "outputs": ["{options.outputPath}", "!{options.outputPath}/.next/cache"],
    "options": {
      "outputPath": "dist/apps/my-app"
    }
  }
}

After running nx run my-app:build, inspecting the Nx cache entry reveals that .next/cache (often 600MB+) is still present:

.nx/cache/<hash>/dist/apps/my-app/.next/cache/   # <-- should not be here

Expected Behavior

The .next/cache directory should not be stored in the Nx cache when excluded via !{options.outputPath}/.next/cache.

GitHub Repo

No response

Steps to Reproduce

  1. Create a Next.js app in an Nx workspace
  2. Configure outputs with negation: ["{options.outputPath}", "!{options.outputPath}/.next/cache"]
  3. Run nx run my-app:build
  4. Inspect the cache: ls .nx/cache/*/dist/apps/my-app/.next/cache
  5. The cache directory is present despite the ! exclusion

Nx Report

Node           : 22.19.0
OS             : darwin-arm64
Native Target  : aarch64-macos
npm            : 10.9.3
daemon         : Disabled

nx                     : 22.5.4
@nx/js                 : 22.5.4
@nx/eslint             : 22.5.4
@nx/workspace          : 22.5.4
@nx/jest               : 22.5.4
@nx/devkit             : 22.5.4
@nx/eslint-plugin      : 22.5.4
@nx/module-federation  : 22.5.4
@nx/next               : 22.5.4
@nx/react              : 22.5.4
@nx/rollup             : 22.5.4
@nx/web                : 22.5.4
@nx/webpack            : 22.5.4
typescript             : 5.1.6
---------------------------------------
Community plugins:
@nx-tools/nx-container : 7.2.1
---------------------------------------
Local workspace plugins:
@nx/workspace
@nx/webpack
@nx/eslint
@nx/rollup
@nx/react
@nx/jest
@nx/next
@nx/web
@nx/js
nx
---------------------------------------
Cache Usage: 738.95 MB / 46.04 GB

Failure Logs

Package Manager Version

No response

Operating System

  • macOS
  • Linux
  • Windows
  • Other (Please specify)

Additional Information

Root Cause

The bug is in the interaction between expand_outputs (packages/nx/src/native/cache/expand_outputs.rs) and _copy in cache.rs:

  1. expand_outputs correctly partitions entries into regular and negated globs
  2. The walker correctly excludes files under the negated path (.next/cache/*)
  3. However, the walker still returns intermediate directory entries like .next itself
  4. In cache.rs put(), each expanded output is copied via _copy() — and when _copy receives a directory, it calls copy_dir_all() which recursively copies everything inside, re-including the negated .next/cache subdirectory

The existing test should_handle_multiple_outputs_with_negation only validates the output of expand_outputs in isolation — it doesn't account for how put() uses directory entries with _copy.

Suggested Fix

In expand_outputs.rs, after collecting found_paths, filter out directory entries that are ancestors of negated paths:

let found_paths = found_paths
    .into_iter()
    .filter(|path| {
        let full_path = directory.join(path);
        if !full_path.is_dir() {
            return true;
        }
        let path_with_slash = format!("{}/", path);
        !negated_globs.iter().any(|neg| neg.starts_with(&path_with_slash))
    })
    .collect::<Vec<_>>();

Environment

  • Nx version: 22.5.4 (likely affects all versions with DbCache)
  • OS: macOS (darwin-arm64)
  • Node: 22.x

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions