How the `astryx swizzle` Command Ejects Component Source for Customization and What Ownership Means
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 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 identifiersourceDir: Absolute path to the component's source filesissuesUrl: Maintainer feedback URL
# 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,*.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:
{
"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
# 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 swizzleextracts 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_COMPONENTerrors when multiple packages export identically-named components, requiring explicit--packageselection. -
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
sanitizeNameandassertWithin, guaranteeing output files cannot escape the target directory. -
Maintenance responsibility fully transfers to the consumer project, though the CLI provides
issuesUrlandghCommandshortcuts 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →