---
title: "Ejection and merging"
description: "Transfer an eligible artifact to application ownership while retaining a reviewable path for upstream changes."
tags: ["cli","eject","merge","ownership","conflicts"]
---

Ejection is the final customization option after configuration and replacing a runtime seam. It moves one eligible source artifact from package ownership to application ownership without disconnecting it from future upstream review.

## Before ejecting

Use the smallest change that satisfies the application:

1. Configure the package through its public options.
2. Replace an explicit bridge or adapter seam.
3. Eject only when neither boundary can represent the required behavior.

Security-critical artifacts cannot be ejected. Signature verification, token validation, and similar package guarantees must remain package-managed so fixes arrive through version updates.

## Select an artifact

```sh
npx playstack eject @playstack/example --target=example-source --dry-run
npx playstack eject @playstack/example --target=example-source
```

The package manifest must declare the artifact as ejectable. The CLI verifies the published hash, writes the application-owned target, saves the installed upstream base beneath `.playstack/base`, and records the relationship in `.playstack/ejected.json`.

After ejection, edit the application target normally. Do not edit the saved base; it exists solely to support deterministic three-way merges.

## Reconcile an upstream change

```sh
npx playstack merge example-source
npx playstack merge --all
```

A merge compares three inputs:

| Input              | Ownership                                                                       |
| ------------------ | ------------------------------------------------------------------------------- |
| Saved base         | The exact upstream source present when the artifact was ejected or last merged. |
| Application target | The repository's current, application-owned implementation.                     |
| New upstream       | The source shipped by the newly installed package version.                      |

A clean merge updates the application target and advances the saved base. An unchanged upstream produces no write.

## Conflict behavior

Conflicts never overwrite the application target with unresolved markers. The CLI writes a conflict report under `.playstack/conflicts` and returns the unsafe-conflict exit code so a human can review the competing changes.

When merging more than two ejected artifacts with `--all`, the CLI defaults to a dry run to avoid applying a large unreviewed ownership change at once.

## Updates and security

`playstack doctor --check` reports when an ejected artifact's upstream hash has changed. Security-tagged upstream changes are called out distinctly.

`playstack update` attempts safe three-way merges after updating installed packages. In pull-request mode, package and managed changes form the primary branch, clean ejected merges form a dependent review branch, and each conflict receives a separate draft branch. Conflict markers are never committed.

Read [Updates and CI](/docs/cli/updates-ci) before automating this workflow.
