How to Use the Swizzle Command to Eject and Modify Astryx Component Source Code

The swizzle command copies component source files from @astryxdesign/core or integration packages into your local project, rewriting relative imports to package references so you can edit JSX, styling, and props directly.

The swizzle command in the facebook/astryx repository provides a safe workflow for ejecting Astryx components from their distributed packages into your source tree. This CLI tool reads the original TypeScript and TSX files, transforms internal dependencies, and writes them to a local directory where you can customize markup, StyleX definitions, and component props without wrapping abstractions.

How the Swizzle Command Works

When you run npx astryx swizzle, the command executes a five-step workflow defined in packages/cli/src/commands/swizzle.mjs to ensure safe, reversible component extraction.

Component Discovery and Package Resolution

The command first identifies which package owns the requested component. Core components live under @astryxdesign/core, while integration components are discovered via the logic in packages/cli/src/lib/component-discovery.mjs. This module maps the component name to its source directory, distinguishing between built-in Astryx primitives and third-party integration packages.

Source Extraction and Import Rewriting

Once located, the command copies all non-test, non-documentation source files (.tsx, .ts, .css) from the component’s directory to your target folder. During this process, the rewriteImports helper (defined at lines 54–68 in packages/cli/src/commands/swizzle.mjs) transforms relative import paths that escape the component folder into package-relative references. For example, ../utils/mergeProps becomes @astryxdesign/core/utils.

Path Safety Validation

To prevent accidental overwrites of system files, the command validates the output directory using packages/cli/src/utils/path-safety.mjs. The target path must resolve inside the current working directory; any attempt to traverse outside triggers a PathSafetyError and aborts the operation.

Maintainer Feedback

After successful extraction, the CLI prints a feedback note generated by the buildFeedback function (lines 80–98 in swizzle.mjs). This includes a link to the component’s issue tracker or a ready-to-run gh command if the repository is hosted on GitHub, preserving the design system’s feedback loop even for ejected components.

Running the Swizzle Command

List Available Components

Before ejecting, inspect which components are available for swizzling:

npx astryx swizzle --list

Eject a Component to Default Location

Copy the Button component source into ./components/astryx:

npx astryx swizzle Button

Specify a Custom Output Directory

Direct the output to a specific folder in your project tree:

npx astryx swizzle Button --output src/custom-components

Force Overwrite Existing Files

Replace previously swizzled components without prompting:

npx astryx swizzle Button -f

Machine-Readable JSON Output

For CI/CD pipelines or automation scripts, use the --json flag to receive structured output:

npx astryx --json swizzle Button
{
  "type": "swizzle.copy",
  "data": {
    "component": "Button",
    "package": "@astryxdesign/core",
    "outputDir": "components/astryx/Button",
    "filesCopied": 5,
    "files": ["Button.tsx","Button.stylex.ts","index.ts","utils.ts","types.ts"],
    "feedback": {
      "issuesUrl": "https://github.com/facebook/astryx/issues/new",
      "ghCommand": "gh issue create --repo facebook/astryx --title \"[Button] Swizzle feedback\""
    }
  }
}

Programmatic Usage

Import the swizzle registration function to embed the command in custom Node.js tooling:

import { registerSwizzle } from '@astryxdesign/cli';
import { Command } from 'commander';

const program = new Command();
registerSwizzle(program);

// Equivalent to `npx astryx swizzle Button`
program.parse(['node', 'astryx', 'swizzle', 'Button']);

Key Implementation Files

Understanding these files helps when debugging swizzle operations or extending the CLI:

  • packages/cli/src/commands/swizzle.mjs – Implements the full workflow including argument parsing, owner resolution, file copying, import rewriting, and feedback generation.
  • packages/cli/src/lib/component-discovery.mjs – Detects component ownership and returns the source directory path for both core and integration components.
  • packages/cli/src/utils/path-safety.mjs – Contains the directory traversal guards that enforce the PathSafetyError when output paths escape the project root.
  • packages/cli/src/lib/json.mjs – Provides the jsonOut helper for emitting structured JSON responses in --json mode.

Summary

  • The swizzle command ejects Astryx components from @astryxdesign/core or integration packages into your local source tree for direct modification.
  • Import rewriting automatically converts relative paths like ../utils/mergeProps into package references (@astryxdesign/core/utils) to maintain dependency integrity.
  • Path safety checks in packages/cli/src/utils/path-safety.mjs prevent the command from writing files outside your project directory.
  • JSON mode (--json) enables machine-readable output suitable for automation scripts and CI pipelines.
  • The original component remains untouched in node_modules; your custom version lives in ./components/astryx or your specified --output directory.

Frequently Asked Questions

What is the difference between swizzling and forking a component?

Swizzling extracts the specific source files of an installed component into your project while maintaining the original package dependency. Forking typically involves copying the entire repository history. With swizzle, you get only the component’s source (.tsx, .ts, .css) with rewritten imports, allowing you to modify implementation details while still receiving updates to the underlying package for non-swizzled components.

Can I swizzle components from third-party Astryx integrations?

Yes. The component-discovery.mjs module detects components from any package following the Astryx integration protocol, not just @astryxdesign/core. When you run npx astryx swizzle ComponentName, the CLI searches across all installed Astryx-compatible packages and resolves the source directory regardless of whether the component is core or third-party.

What happens if I swizzle a component that already exists in my output directory?

By default, the command warns you about existing files and aborts to prevent accidental overwrites. Use the -f (force) flag to overwrite existing swizzled components with the current package version. This replaces your local modifications with the upstream source, so commit your changes before forcing an update.

How does the swizzle command handle import paths after ejection?

The rewriteImports function in packages/cli/src/commands/swizzle.mjs analyzes all import statements in the copied files. Any relative imports that reference files outside the component directory (such as shared utilities) are rewritten to point to the owning package’s public exports. This ensures your swizzled component continues to resolve dependencies correctly without requiring you to manually fix broken ../ paths.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →