# How Vite+ Handles Task Dependency Resolution with the Topological Flag in Monorepos

> Vite+ automatically resolves monorepo task dependencies using a topological sort. Learn how it ensures correct execution order for your builds and commands.

- Repository: [VoidZero/vite-plus](https://github.com/voidzero-dev/vite-plus)
- Tags: internals
- Published: 2026-03-16

---

**Vite+ automatically resolves task dependencies in monorepos by building a directed workspace graph from package.json relationships and applying topological sorting to ensure dependencies execute before dependents when running commands with `--recursive` or `--filter`.**

The `voidzero-dev/vite-plus` toolchain introduces sophisticated task orchestration for JavaScript monorepos through its topological dependency resolution system. When executing commands across multiple packages, Vite+ analyzes workspace relationships defined in [`package.json`](https://github.com/voidzero-dev/vite-plus/blob/main/package.json) to determine the optimal execution order. This ensures that build artifacts from dependency packages are available before dependent packages begin their tasks.

## Workspace Graph Construction and Implicit Dependencies

Vite+ builds a *workspace graph* that represents each package as a node and the **package.json** relationships (`dependencies`, `devDependencies`, `peerDependencies`, etc.) as directed edges. When a command is run with `--recursive` or `--filter`, Vite+ must decide **in which order** to execute the selected packages.

### Implicit Dependencies in Topological Mode

When the topological flag is enabled (the default for recursive runs), every workspace-to-workspace dependency edge is converted into an *implicit* task dependency. According to the project documentation in [`CLAUDE.md`](https://github.com/voidzero-dev/vite-plus/blob/main/CLAUDE.md) (lines 46-53), if package **A** depends on package **B**, then `A#build` automatically depends on `B#build`.

This behavior ensures that:
- Build tasks in dependency packages complete before downstream packages start
- Dev dependencies are prepared before their consumers execute
- Peer dependency constraints are respected during task execution

### Default Topological Ordering for Recursive Commands

When executing `vp exec -r …` or `vp run -r …`, Vite+ **automatically** applies topological ordering. The RFC documented in [`rfcs/exec-command.md`](https://github.com/voidzero-dev/vite-plus/blob/main/rfcs/exec-command.md) (lines 11-19) specifies that the topological sort uses `petgraph::algo::toposort` on the `FilterResolution.package_subgraph`, ensuring that dependencies are executed before dependents.

## Implementation of the Topological Sort Algorithm

The core resolution logic resides in [`packages/cli/binding/src/exec/workspace.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/exec/workspace.rs), where Vite+ implements a robust sorting mechanism with cycle detection.

### Building the Workspace Graph

The function `vite_workspace::load_package_graph` constructs a `DiGraphMap<PackageNodeIndex, ()>` that stores all packages and their intra-workspace dependency edges. This directed graph serves as the foundation for all subsequent topological operations.

### Subgraph Extraction and Filtering

After the user applies filters (`--recursive`, `--filter`, or defaults to the current package), the `FilterResolution` struct contains a `package_subgraph` field. This subgraph includes only the selected nodes and the edges relevant to those nodes, allowing targeted execution within large monorepos.

### The topological_sort_packages Function

The critical sorting logic appears in lines 321-335 of [`workspace.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/workspace.rs). The `topological_sort_packages` function implements a two-phase approach:

```rust
fn topological_sort_packages(subgraph: &DiGraphMap<PackageNodeIndex, ()>) -> Vec<PackageNodeIndex> {
    match petgraph::algo::toposort(subgraph, None) {
        Ok(mut sorted) => {
            sorted.reverse();            // deps-first order
            sorted
        }
        Err(_cycle) => {
            // Fallback for cycles – SCCs in reverse topological order
            petgraph::algo::tarjan_scc(subgraph).into_iter().flatten().collect()
        }
    }
}

```

The function first attempts `petgraph::algo::toposort`, which returns nodes in *dependents-first* order. Vite+ reverses this list to ensure **dependencies appear first**. If the graph contains a cycle, the algorithm falls back to **Tarjan's strongly-connected-components** algorithm, yielding SCCs in reverse topological order to preserve correct dependencies-first ordering for everything outside the cycle.

### Handling Circular Dependencies

When `toposort` detects a cycle, Vite+ does not fail. Instead, it uses `petgraph::algo::tarjan_scc` to identify strongly connected components. The RFC documentation explains that this preserves a correct *dependencies-first* order for acyclic portions of the graph, while the intra-cycle order is left arbitrary since no linear order can satisfy a circular dependency.

## CLI Flags for Execution Order Control

Vite+ provides several flags to override the default topological behavior when running tasks across multiple packages.

### Running Tasks in Parallel

The `--parallel` flag (defined in [`packages/cli/binding/src/exec/args.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/exec/args.rs)) **skips** topological ordering entirely and spawns all selected packages concurrently. This is useful for tasks that do not depend on build artifacts, though output may be interleaved:

```bash

# Execute command in all packages simultaneously

vp exec -r --parallel -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

```

### Reverse Topological Order

The `--reverse` flag reverses the computed topological order, causing dependents to execute before their dependencies. This is particularly useful for cleanup or teardown scripts:

```bash

# Run dependents first, then dependencies

vp exec -r --reverse -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

```

### Disabling Implicit Dependencies

The `--no-topological` flag (available on `vp run` commands) disables the creation of implicit dependencies from [`package.json`](https://github.com/voidzero-dev/vite-plus/blob/main/package.json) relationships. When used, only **explicit** task dependencies defined in [`vite-task.json`](https://github.com/voidzero-dev/vite-plus/blob/main/vite-task.json) are honored:

```bash

# Ignore workspace dependencies, use only vite-task.json dependsOn

vp run build -r --no-topological

```

## Practical Examples

The following commands demonstrate common topological execution patterns in Vite+ monorepos:

```bash

# Run a command in every workspace package, respecting package.json deps

vp exec -r -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

# Packages are invoked in dependency-first order (e.g., lib → app)

# Reverse the order – useful for teardown scripts

vp exec -r --reverse -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

# Dependents run first, then their dependencies

# Execute in parallel – ignore topological order

vp exec -r --parallel -- node -e "console.log(process.env.VITE_PLUS_PACKAGE_NAME)"

```

## Summary

- Vite+ constructs a directed workspace graph from [`package.json`](https://github.com/voidzero-dev/vite-plus/blob/main/package.json) dependencies to model package relationships.
- The `topological_sort_packages` function in [`packages/cli/binding/src/exec/workspace.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/exec/workspace.rs) uses `petgraph::algo::toposort` to establish a dependencies-first execution order.
- When cycles are detected, the system falls back to Tarjan's SCC algorithm to maintain correct ordering for acyclic portions of the graph.
- The `--recursive` flag enables topological ordering by default, while `--parallel`, `--reverse`, and `--no-topological` provide explicit control over execution semantics.
- Implicit task dependencies are automatically derived from workspace package relationships unless explicitly disabled.

## Frequently Asked Questions

### What happens when Vite+ detects a circular dependency in the workspace?

When `petgraph::algo::toposort` detects a cycle in the workspace graph, Vite+ falls back to `petgraph::algo::tarjan_scc` as implemented in [`packages/cli/binding/src/exec/workspace.rs`](https://github.com/voidzero-dev/vite-plus/blob/main/packages/cli/binding/src/exec/workspace.rs). This algorithm identifies strongly connected components and emits them in reverse topological order, preserving correct dependencies-first ordering for packages outside the cycle while handling the circular portion as a single unit.

### How does the topological flag interact with explicit task dependencies in vite-task.json?

The topological flag creates **implicit** dependencies based on [`package.json`](https://github.com/voidzero-dev/vite-plus/blob/main/package.json) relationships, while [`vite-task.json`](https://github.com/voidzero-dev/vite-plus/blob/main/vite-task.json) defines **explicit** dependencies through the `dependsOn` field. By default, both are respected. However, using `--no-topological` on `vp run` commands disables implicit dependencies, causing Vite+ to honor only the explicit `dependsOn` entries defined in [`vite-task.json`](https://github.com/voidzero-dev/vite-plus/blob/main/vite-task.json).

### Can I run dependent packages before their dependencies in Vite+?

Yes. Passing the `--reverse` flag to `vp exec` or `vp run` reverses the topological order, causing dependents to execute before their dependencies. This is useful for cleanup tasks, cache invalidation, or any operation where you need to process packages in the opposite direction of their dependency graph.

### Does topological sorting apply to all Vite+ commands by default?

No. Topological sorting is automatically applied only when using `--recursive` (`-r`) or `--filter` flags that select multiple packages. Single-package execution does not trigger the topological sort. Additionally, you can explicitly disable topological ordering with `--parallel` (for concurrent execution) or `--no-topological` (to ignore workspace dependencies).