# How the Astryx Upgrade Command Runs Version Migration Codemods

> Learn how the Astryx upgrade command automates version migration codemods. It detects your Astryx version, finds codemod transforms, and applies them to your source code.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: internals
- Published: 2026-07-02

---

**The `astryx upgrade` command automates version-to-version migrations for Astryx projects by detecting your installed core package version, collecting applicable codemod transforms for the version range, and executing them against your source tree.**

The `astryx upgrade` command is the official CLI tool for migrating Astryx codebases between versions. According to the facebook/astryx source code, it orchestrates a three-step pipeline that handles everything from version detection to automated code transformation. This command eliminates manual refactoring when upgrading `@astryxdesign/core` by executing **codemods**—automated scripts that transform your source code to match new API patterns.

## The Three-Step Upgrade Pipeline

When you execute `astryx upgrade`, the command implementation in `packages/cli/src/commands/upgrade.mjs` performs a standardized workflow:

1. **Detect the installed core package** – The command reads the version of `@astryxdesign/core` (or legacy `@xds/core`) from `node_modules` to determine the target version.
2. **Run codemods** – Using the version range `--from <old-version>` to the detected version, it loads transformation manifests from the registry and executes each codemod against your source tree.
3. **Refresh agent docs** – After codemods finish, it regenerates [`AGENTS.md`](https://github.com/facebook/astryx/blob/main/AGENTS.md) or [`CLAUDE.md`](https://github.com/facebook/astryx/blob/main/CLAUDE.md) files if they exist in your project.

## Detailed Execution Flow

### Option Parsing and Validation

The command accepts multiple flags to control the migration behavior. In `packages/cli/src/commands/upgrade.mjs` (lines 17–27), the CLI defines options including `--from`, `--apply`, `--force`, `--codemod`, `--skip-codemod`, `--integration`, `--path`, and `--install-deps`.

The `--from` flag is strictly validated using `isValidSemver()` from `packages/cli/src/utils/semver.mjs`. If you provide an invalid semver string, the command aborts immediately (lines 88–96).

### Version Detection

Before running any transforms, `detectInstalledTargetVersion()` (lines 60–78) scans `node_modules/@astryxdesign/core` (falling back to `@xds/core` for legacy projects) for a [`package.json`](https://github.com/facebook/astryx/blob/main/package.json) file and extracts the `version` field. This becomes the target version for the migration range.

### Codemod Selection and Registry

The registry in `packages/cli/src/codemods/registry.mjs` stores per-version manifests containing available transforms. The function `getTransformsBetween(from, to)` (line 42) walks the version list and merges all transforms whose versions fall between your supplied `--from` version and the detected target version.

Each manifest entry contains `{name, transform, meta, optional}` properties. Optional codemods are skipped unless you explicitly request them via the `--codemod` flag.

### Running Core Codemods

The `runCodemods()` function in `packages/cli/src/codemods/runner.mjs` (lines 71–134) handles the actual transformation:

- Loads `jscodeshift` to parse and transform JavaScript/TypeScript files
- Iterates over each version manifest
- Reads source files from the `--path` directory
- Applies transforms and validates output
- Writes changes only when `--apply` is set (dry-run by default)

If you specify `--integration`, the command additionally discovers and executes integration-specific codemods via `discoverIntegrationCodemods` and `runIntegrationCodemods` (lines 45–48).

### Post-Codemod Hooks and Documentation

After transformations complete, the command executes any `postCodemod` hooks defined in your Astryx configuration (lines 86–136). It then triggers `installAgentDocs` to regenerate [`AGENTS.md`](https://github.com/facebook/astryx/blob/main/AGENTS.md) or [`CLAUDE.md`](https://github.com/facebook/astryx/blob/main/CLAUDE.md) files (lines 49–50), ensuring your documentation reflects updated component APIs.

## Common Usage Examples

### Preview Changes Without Writing Files

By default, the upgrade command runs in dry-run mode, showing what would change without modifying files:

```bash

# After installing the new @astryxdesign/core version

astryx upgrade --from 0.0.6

```

This reads the installed core version (e.g., 0.0.8), gathers all codemods from 0.0.6 → 0.0.8, and prints a preview to stdout.

### Apply Migrations to Source Files

To actually write the transformed code back to disk:

```bash
astryx upgrade --from 0.0.6 --path ./src --apply

```

The `--apply` flag commits changes. Always run without `--apply` first to review the migration impact.

### Run a Specific Codemod

To execute only one transform rather than the full version range:

```bash
astryx upgrade --from 0.0.6 --codemod rename-stack-element-to-as --apply

```

This targets only the `rename-stack-element-to-as` transform, useful when you need granular control over large migrations.

### Skip Failing Codemods

If a specific codemod causes issues, exclude it while running others:

```bash
astryx upgrade --from 0.0.6 --skip-codemod rename-action-props --apply

```

The `--skip-codemod` flag accepts a comma-separated list of transform names to omit.

### CI-Friendly Automation

For automated pipelines where interactive prompts are not available:

```bash
astryx upgrade --from 0.0.6 --install-deps --apply

```

The `--install-deps` flag automatically installs `jscodeshift` inside CI containers without requiring manual confirmation.

### List Available Transforms

To see all registered codemods before running:

```bash
astryx upgrade --list

```

This prints a deduplicated list of every codemod registered by the core package and any loaded integrations.

## Summary

- **`astryx upgrade`** is the official CLI entry point for automated version migrations in the Astryx ecosystem.
- The command reads your current `@astryxdesign/core` version from `node_modules` and calculates the transformation range from your `--from` parameter.
- **Codemods** are selected from `packages/cli/src/codemods/registry.mjs` using `getTransformsBetween()` and executed via the runner in `packages/cli/src/codemods/runner.mjs`.
- Dry-run mode is the default; you must pass `--apply` to write file changes.
- The command supports granular control via `--codemod`, `--skip-codemod`, and `--integration` flags.
- Post-migration, it automatically refreshes agent documentation ([`AGENTS.md`](https://github.com/facebook/astryx/blob/main/AGENTS.md), [`CLAUDE.md`](https://github.com/facebook/astryx/blob/main/CLAUDE.md)) to reflect API changes.

## Frequently Asked Questions

### What happens if I don't specify the `--from` version?

The command requires `--from` to establish the version range for codemod selection. If omitted, the CLI will error out after validating arguments (lines 88–96 in `upgrade.mjs`). You must specify the version you are migrating from so the registry can determine which transforms to apply.

### How does the command handle breaking changes in codemods?

Breaking changes are managed through the registry's version manifests. Each codemod is tagged with a target version. The `getTransformsBetween()` function only applies transforms relevant to your specific version range. Optional codemods (marked with `optional: true`) are skipped by default unless explicitly requested with `--codemod`, preventing unexpected breaking changes.

### Can I run integration-specific codemods without core codemods?

No, the current implementation in `packages/cli/src/commands/upgrade.mjs` runs core codemods first, then optionally runs integration codemods if `--integration` is provided. There is no flag to run only integration codemods while skipping core transforms. However, you can use `--skip-codemod` to skip specific core transforms that you don't want to execute.

### Where does the command look for the installed core package?

The `detectInstalledTargetVersion()` function scans `node_modules/@astryxdesign/core/package.json` for the version field. If that package is not found, it falls back to the legacy `@xds/core` package path (lines 60–78). This detection happens automatically before any codemods are selected or executed.