# How the `astryx swizzle` Command Ejects Component Source for Customization and What Ownership Means

> Learn how the astryx swizzle command ejects component source code for customization. Understand ownership implications when multiple packages offer the same component.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: how-to-guide
- Published: 2026-08-04

---

**The `astryx swizzle` command extracts compiled Astryx component source files into your project, rewrites their internal imports to maintain functionality, and forces you to explicitly resolve ownership when multiple packages provide the same component.**

The `astryx swizzle` command is the official escape hatch for developers who need to customize Astryx components beyond what props and themes allow. According to the [facebook/astryx](https://github.com/facebook/astryx) source code, this CLI tool performs a surgical extraction of source files, safeguards against ambiguous ownership, and transforms internal package references so swizzled components remain buildable in consumer projects.

## What `astryx swizzle` Does

Swizzling moves a component from **managed dependency** to **project-owned source**. This is irreversible—you take full responsibility for updates, bug fixes, and styling compatibility.

The command operates through three distinct phases implemented in `packages/cli/api/swizzle/copy/copy.mjs`:

### Phase 1: Resolve Component Ownership

The `resolveOwners` function scans all candidate packages and builds a list of potential owners. Each owner record contains:

- `packageName`: The npm package identifier
- `sourceDir`: Absolute path to the component's source files
- `issuesUrl`: Maintainer feedback URL

```bash

# Default resolution (core package only)

npm run astryx -- swizzle Button

# Explicit package selection when duplicates exist

npm run astryx -- swizzle Button --package @myorg/custom-integration

```

If multiple packages export a component with identical names, the CLI throws `ERR_AMBIGUOUS_COMPONENT`. You must disambiguate with `--package`. This guard prevents accidental modification of integration code when you intended to customize core components (lines 29-36 in `copy.mjs`).

### Phase 2: Copy and Transform Source Files

The selected owner's source directory is processed through `isExcludedFromCopy`, which filters out:

- Test files (`*.test.*`, `*.spec.*`)
- Documentation ([`README.md`](https://github.com/facebook/astryx/blob/main/README.md), `*.doc.mjs`)
- Internal metadata

Remaining files undergo **import rewriting** via `rewriteImports` (lines 56-90). Relative imports that escape the component directory are converted to package-prefixed imports:

| Original Import | Rewritten Import |
|---------------|----------------|
| `../utils/mergeProps` | `@astryxdesign/core/utils` |
| `../../hooks/useTheme` | `@astryxdesign/core/hooks` |

This ensures swizzled components resolve dependencies correctly even after leaving their original package structure.

The CLI also detects **StyleX usage** (`@stylexjs/stylex`). When found, it sets `usesStyleX: true` in the receipt and prints a warning that your project now requires a StyleX compiler to generate CSS.

Files are written to `--output` (default: `./components/astryx/<Component>/`). Overwrites require `-f` or `--overwrite`.

### Phase 3: Generate Receipt and Feedback Channel

The command returns a structured `swizzle.copy` receipt and constructs a **maintainer feedback** prompt:

```json
{
  "type": "swizzle.copy",
  "data": {
    "component": "Button",
    "package": "@astryxdesign/core",
    "outputDir": "components/astryx/Button",
    "filesCopied": 5,
    "usesStyleX": true,
    "feedback": {
      "issuesUrl": "https://github.com/facebook/astryx/issues/new",
      "ghCommand": "gh issue create --repo facebook/astryx --title \"[Button] Swizzle feedback\""
    }
  }
}

```

The `ghCommand` provides a one-line shortcut to file issues against the original package—critical for reporting bugs in swizzled components back to upstream maintainers (lines 90-106, 171-179).

## Ownership Implications and Safety Guards

Understanding **who owns a component** determines maintenance burden, update cadence, and support channels.

### Core vs. Integration Packages

| Owner Type | Characteristics | Typical Use Case |
|-----------|-----------------|----------------|
| **Core (`@astryxdesign/core`)** | Facebook-maintained, semantically versioned, comprehensive tests | Starting point for most customizations |
| **Integration** | Third-party or internal, may diverge from core API, faster iteration cycles | Extending core with domain-specific functionality |

When both provide the same component name, the CLI refuses to proceed without `--package`. This **ambiguity guard** eliminates silent errors where you modify the wrong source tree.

### Path Safety and Security

The component name passes through `sanitizeName` to strip path traversal sequences. The `assertWithin` utility verifies all output files remain inside the specified directory, preventing escape attacks even with malicious package configurations.

### Build System Consequences

Swizzling has **downstream build implications**:

| Condition | Required Consumer Change |
|-----------|------------------------|
| Component uses StyleX | Add StyleX compiler to build pipeline per `packages/cli/assets/docs/styling.doc.mjs` |
| Component uses internal utils | Ensure `@astryxdesign/core` remains installed for rewritten imports |
| Component has peer dependencies | Manually install and version-lock those dependencies |

The receipt's `usesStyleX` boolean acts as a checklist item for build configuration review.

### Maintenance Responsibility Transfer

Once swizzled, the component is **your code**. You lose:

- Automatic updates from the source package
- Verified compatibility with new Astryx core releases
- Guarantees around accessibility, performance, and browser support

The `issuesUrl` in the receipt exists solely for **upstream feedback**, not support. Facebook's issue tracker will not address bugs in your modified implementation.

## Complete Usage Examples

```bash

# Basic swizzle with default output

npm run astryx -- swizzle Button

# Force overwrite of previously swizzled component

npm run astryx -- swizzle Card -f

# Custom output directory for organizational purposes

npm run astryx -- swizzle Modal --output ./src/ui/legacy

# Disambiguate when multiple packages export DataTable

npm run astryx -- swizzle DataTable --package @acme/data-viz

```

## Source File Reference

| File | Purpose |
|------|---------|
| `packages/cli/api/swizzle/copy/copy.mjs` | Core implementation: owner resolution, import rewriting, file I/O, feedback generation |
| `packages/cli/api/swizzle/copy/copy.test.mjs` | Test coverage for path safety, overwrite logic, and ownership disambiguation |
| `packages/cli/clients/cli/commands/swizzle.mjs` | CLI argument parsing and flag validation |
| `packages/cli/api/swizzle/swizzle.mjs` | API dispatcher routing to `swizzleList` or `swizzleCopy` |
| `packages/cli/foundation/discovery/component-discovery.mjs` | Component metadata discovery across core and integration packages |
| `packages/cli/assets/docs/styling.doc.mjs` | StyleX build setup documentation |

## Summary

- **`astryx swizzle` extracts component source** into your project for direct modification, implementing three phases: owner resolution, file transformation with import rewriting, and receipt generation.

- **Ownership ambiguity is aggressively prevented** through `ERR_AMBIGUOUS_COMPONENT` errors when multiple packages export identically-named components, requiring explicit `--package` selection.

- **Import rewriting preserves functionality** by converting relative cross-package imports to absolute package references, ensuring swizzled components continue resolving dependencies correctly.

- **StyleX detection triggers build warnings** because swizzled StyleX components require consumer-side compiler configuration to generate CSS.

- **Path safety is enforced** through `sanitizeName` and `assertWithin`, guaranteeing output files cannot escape the target directory.

- **Maintenance responsibility fully transfers** to the consumer project, though the CLI provides `issuesUrl` and `ghCommand` shortcuts for upstream feedback.

## Frequently Asked Questions

### What happens if I don't specify `--package` and multiple packages have the same component?

The CLI aborts with `ERR_AMBIGUOUS_COMPONENT` and lists the conflicting packages. You must rerun with `--package <name>` to explicitly choose which source tree to extract. This prevents accidental modification of integration components when you intended to customize core behavior.

### Why are some imports rewritten during swizzling?

Relative imports that reference files outside the component directory (like `../utils/mergeProps`) would break once the component leaves its original package structure. The `rewriteImports` function converts these to package-prefixed imports (`@astryxdesign/core/utils`) so they resolve through your installed dependencies rather than relative filesystem paths.

### Do I need to install anything extra after swizzling a StyleX component?

Yes. The receipt's `usesStyleX: true` flag indicates your project must integrate a StyleX compiler into its build pipeline. The CLI prints a pointer to `packages/cli/assets/docs/styling.doc.mjs` for setup instructions. Without this, your swizzled component's styles will not generate CSS at build time.

### Can I swizzle back to the package version if I made a mistake?

No—swizzling is one-directional. There is no "unswizzle" command. To revert, delete your swizzled directory and reinstall the package. Consider version-controlling your project before swizzling, or use a temporary output directory to evaluate the extracted source before committing to customization.