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

# Multi-File and Multi-Repo

> Coordinate edits across files and repositories with jssgTransform, rename, and matrix orchestration.

Coordinate changes beyond a single file: secondary-file transforms, renames, and repo-scoped matrix runs.

## Multi-Repo Orchestration

Use multi-repo orchestration when your codemod must coordinate changes across multiple repositories—such as updating shared libraries, enforcing consistency, or applying repo-specific logic. This approach streamlines large-scale migrations and ensures changes are applied uniformly.

```ts theme={null}
import type { Codemod } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

const codemod: Codemod<TSX> = async (root, options) => {
  const filePath = root.filename();
  const repoName = options.matrixValues?.repo_name;
  
  // Apply repo-specific transformations
  if (repoName === "frontend-app") {
    // Frontend-specific logic
  } else if (repoName === "backend-api") {
    // Backend-specific logic
  }
};

export default codemod;
```

## Multi-File Transforms

Sometimes a codemod needs to modify multiple files in a coordinated way. For example, renaming a `.less` file to `.css` and updating every import that references it. JSSG provides two mechanisms for this:

### `jssgTransform` — Transform Secondary Files

Use `jssgTransform()` to apply a transform function to another file from within your main transform. The secondary file's changes are collected and applied atomically alongside the primary file's changes.

```ts theme={null}
import { jssgTransform } from "codemod:ast-grep";
import type { Codemod, Edit } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";
import type CSS from "codemod:ast-grep/langs/css";

const migrateStyles: Codemod<CSS> = async (root) => {
  // Rename the file from .less to .css
  root.rename(root.filename().replace('.less', '.css'));
  // Optionally transform the content
  return transformedContent;
};

const codemod: Codemod<TSX> = async (root) => {
  const rootNode = root.root();
  const edits: Edit[] = [];

  // Find imports referencing .less files
  const lessImports = rootNode.findAll({
    rule: { pattern: "import $SOURCE" },
  });

  for (const imp of lessImports) {
    const source = imp.getMatch("SOURCE");
    if (!source?.text().includes(".less")) continue;

    const lessPath = source.text().slice(1, -1);

    // Transform the secondary file
    await jssgTransform(migrateStyles, lessPath, "css");

    // Update the import path in this file
    edits.push(source.replace(`"${lessPath.replace('.less', '.css')}"`));
  }

  return edits.length > 0 ? rootNode.commitEdits(edits) : null;
};

export default codemod;
```

<Info>
  `jssgTransform` is a no-op in test mode — it returns `null` without reading or writing files. This means test cases only verify the primary transform. To test secondary transforms, write separate test cases for them.
</Info>

### `root.rename()` — Rename the Current File

Use `root.rename(newPath)` to rename the file currently being processed. This is useful for file extension conversions (`.js` → `.ts`, `.less` → `.css`, `.cjs` → `.mjs`).

```ts theme={null}
const codemod: Codemod<CSS> = async (root) => {
  // Rename .less → .css
  root.rename(root.filename().replace('.less', '.css'));

  // Return modified content, or null for rename-only
  return null;
};
```

**Rules:**

* Relative paths resolve against the file's parent directory.
* Absolute paths are used as-is.
* The resolved path must stay within the target directory.
* `rename()` can only be called once per file.

See the [API Reference](/community/jssg/reference#file-renaming) for the full behavior matrix.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.