Skip to content
Arxo Arxo

Grouping

Grouping controls how the import graph aggregates nodes: by file, by folder (at a chosen depth), or by package (workspace package name). This determines what “one module” means for metrics like SCC, propagation cost, and centrality.

  • File-level — Every file is a node. More nodes, more noise; cycles and coupling are at the level of individual files.
  • Folder-level — Files under the same folder (up to a depth) become one node. You get path-based “module” boundaries; cycles and metrics reflect dependencies between those groups.
  • Package-level — Files are grouped by workspace package (e.g. npm/pnpm/yarn package name). One node per package; ideal for monorepos where each package is a unit.

For most projects, folder grouping with depth 2 (or 1) or package grouping (in a monorepo) gives more meaningful architecture signals than file-level.

Under data.import_graph:

data:
import_graph:
group_by: folder # "file" | "folder" | "package"
group_depth: 2 # used only when group_by: folder
ValueMeaning
fileOne node per file. No aggregation.
folderNodes are folders; files are grouped by parent path. group_depth controls how many path segments define a group (e.g. depth 1 = immediate parent, depth 2 = two levels up).
packageNodes are workspace packages. Arxo detects the workspace (e.g. from package.json workspaces, pnpm-workspace, etc.) and assigns each file to a package; files in the same package become one node. Files that don’t belong to any workspace package stay as single-file nodes.
  • Only used when group_by: folder.
  • 1 — Group by immediate parent directory (e.g. src/components/Button.tsx → node components).
  • 2 — Group by two levels (e.g. src/app/dashboard/page.tsx → node app/dashboard). Default in schema is 2.
  • Higher values — Deeper folder hierarchy = larger “modules.”

File-level:

import_graph:
group_by: file

→ Nodes: src/a.ts, src/b.ts, src/c.ts. Cycles are file-to-file.

Folder, depth 1:

import_graph:
group_by: folder
group_depth: 1

→ All files in src/components/ become one node “components”; files in src/utils/ become “utils”. Edges are between these folder-nodes.

Folder, depth 2:

import_graph:
group_by: folder
group_depth: 2

→ Good for “feature” boundaries (e.g. src/app/dashboard, src/app/auth) when you’re not using workspace packages.

Package (monorepo):

import_graph:
group_by: package

→ One node per workspace package (e.g. @myapp/web, @myapp/api, @myapp/shared). Uses workspace detection (npm/pnpm/yarn workspaces, etc.). Files outside any package remain one node per file.

  • package — Use in monorepos when the unit of architecture is the workspace package (e.g. npm/pnpm/yarn packages). Nodes are package names; edges are package-to-package. Requires workspace detection to succeed for your repo.
  • folder — Use when you want path-based grouping without relying on package manifests. You control granularity with group_depth. Works in any repo.
  • SCC — Cycle size and count are in terms of grouped nodes. With folder or package grouping, “no cycles” means no cycle between those modules.
  • Propagation cost, centrality — Same: fan-in, fan-out, and propagation are over the chosen nodes.
  • Policy — Invariants like scc.max_cycle_size == 0 apply to whatever grouping you set; same config can be used with different grouping for different views (e.g. file-level for drill-down, folder or package for CI).

In Arxo’s config schema, group_by defaults to folder and group_depth to 2, so new configs get folder-based grouping unless overridden.