# Utility Commands

> Copy, discover, migrations, init, and debug command reference.
This page covers commands that do not fit the main sync/migrate/backup groups.

## copy [#copy]

```bash
sb-mig copy stories \
  --from 12345 \
  --to 67890 \
  --source blog/post-1 \
  --destination imported

sb-mig copy stories \
  --from 12345 \
  --to 67890 \
  --source blog \
  --destination imported \
  --with-assets

sb-mig copy assets \
  --from 12345 \
  --to 67890 \
  --all

sb-mig copy assets \
  --from 12345 \
  --to 67890 \
  --asset hero.jpg

sb-mig copy assets \
  --from 12345 \
  --to 67890 \
  --assetFolder Marketing/Heroes

sb-mig copy assets \
  --from 12345 \
  --to 67890 \
  --referenced-by-stories \
  --source blog

sb-mig copy assets \
  --from 12345 \
  --to 67890 \
  --all \
  --dry-run \
  --outputPath sbmig/copy-plans/assets-copy.json
```

`copy stories` copies a source story or folder tree into a target folder.
`copy assets` copies or plans all assets and asset folders. Apply mode writes
asset folders and assets to the target space, finalizes asset uploads, and stores
durable source-to-target manifests under `.sb-mig/copy/<source>/<target>/`.

### Strategies [#strategies]

| Story selector              | Mode       | Behavior                                                                        |
| --------------------------- | ---------- | ------------------------------------------------------------------------------- |
| `--source blog/post-1`      | `subtree`  | Copy one story and attach it under `--destination`.                             |
| `--source blog`             | `subtree`  | Copy the folder story and all descendants under `--destination`.                |
| `--source blog/*`           | `children` | Copy the folder children under `--destination` without copying the folder root. |
| `--source blog --mode self` | `self`     | Copy only the selected story or folder shell.                                   |

### Options [#options]

| Flag                      | Type                             | Effect                                                                                                   |
| ------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `--from`                  | string                           | Source Storyblok space ID. Falls back to configured `spaceId`.                                           |
| `--to`                    | string                           | Target Storyblok space ID. Falls back to configured `spaceId`.                                           |
| `--source`                | string                           | Source story or folder `full_slug`. Use `folder/*` for children-only story copy.                         |
| `--destination`           | string                           | Existing target folder `full_slug` to attach copied stories under. Omit, `/`, or `root` for target root. |
| `--mode`                  | `subtree`, `children`, or `self` | Story copy mode. Defaults to `subtree`; `folder/*` defaults to `children`.                               |
| `--with-assets`           | boolean                          | For `copy stories`, copy referenced assets first and relink copied stories to target asset references.   |
| `--all`                   | boolean                          | Select all assets and asset folders. Use one asset selector family per run.                              |
| `--asset`                 | string                           | Select one source asset by numeric ID, exact Storyblok asset URL, or unique file name. Repeatable.       |
| `--assetFolder`           | string                           | Select one source asset folder by numeric ID or path. Includes descendants and assets in that subtree.   |
| `--referenced-by-stories` | boolean                          | For `copy assets`, select source-space assets referenced by the selected story/folder scope.             |
| `--dry-run`               | boolean                          | Preview paths, manifest-mapped references, and likely conflicts without Storyblok writes.                |
| `--outputPath`            | string                           | Write a JSON dry-run or apply report to a local path.                                                    |

Legacy story-copy aliases still work: `--sourceSpace` for `--from`,
`--targetSpace` for `--to`, `--what` for `--source`, and `--where` for
`--destination`.

`--source` must resolve to an existing story or folder. `--destination` must
resolve to an existing folder in the target space unless it is omitted, `/`, or
`root`. `copy stories` writes copied stories to the target space unless
`--dry-run` is passed and writes story ID/UUID manifests under
`.sb-mig/copy/<source>/<target>/` during apply. It also rewrites mapped asset
and story references in copied target story content after manifests exist.
`copy stories --with-assets` scans the selected stories with source component
schemas, copies referenced assets and their asset-folder ancestors first, then
uses the manifests to relink copied story asset fields to target asset IDs and
filenames. Dry-run output classifies asset references as `mapped`, `planned`, or
`unresolved` and separates reference occurrences from unique assets in the JSON
`assetReferenceSummary`. It also reports foreign Storyblok asset space IDs
detected from asset URLs without trying to copy from those spaces. With
`--with-assets`, referenced assets and folders are marked as `match` when an
existing manifest mapping can be reused. Without `--with-assets`, run
`copy assets` first when copied stories should point to target-space assets.
`copy assets` writes target asset folders/assets unless `--dry-run` is passed.
It supports `--all`, `--asset`, `--assetFolder`, and
`--referenced-by-stories`. `--asset` includes the selected asset's folder
ancestors. `--assetFolder` includes the selected folder, its descendants,
ancestor folders, and assets inside the selected subtree.
`--referenced-by-stories` requires `--source`; it scans the selected story or
folder scope with source component schemas and copies only source-space assets
referenced by that scope. `copy assets` matches by manifest first, then by safe
target folder path or unique target asset file name before creating. `--all`
paginates through source assets and asset folders before planning or applying,
so large spaces are not limited to the first Storyblok Management API page.
Apply mode writes JSONL manifests under `.sb-mig/copy/<source>/<target>/`.

### Resilience and failure reporting [#resilience-and-failure-reporting]

`copy stories` apply mode processes the whole selected tree even when individual
stories fail. If a story update is rejected — for example a `422` when the target
space schema does not allow a component used in the story — the command records
the failure, keeps copying the remaining stories, and then exits non-zero at the
end with a summary of every story that failed. A failing parent keeps its
already-created target shell, so its descendants are still copied under it. One
broken story no longer aborts a large copy.

Failed story updates identify the offending component in place: the component
name, the field it sits in, its parent component, its `_uid`, and its path in the
story content (for example `content.body[3].tabs[1]`), together with the source
and target story IDs, so the exact blok can be located.

### Predicting schema rejections in dry-run [#predicting-schema-rejections-in-dry-run]

`copy stories --dry-run` validates every source component against the target
space component schema before you apply. The JSON report adds a
`componentCompatibility` block and a `summary.componentIssues` count, and the
plan warns when a component would be rejected at write time:

| Warning code                     | Meaning                                                                                 |
| -------------------------------- | --------------------------------------------------------------------------------------- |
| `component_missing_in_target`    | A component used in a source story does not exist in the target space schema.           |
| `component_not_allowed_in_field` | A component sits in a bloks field whose target schema restricts the allowed components. |

Each finding records the component, the reason, the source story `full_slug`, the
field, the parent component, the `_uid`, and the content path. Tag-based field
whitelists are skipped to avoid false positives, and the check is skipped
entirely when the target space returns no components.

## discover [#discover]

### Components [#components]

```bash
sb-mig discover components --all
sb-mig discover components --all --write
sb-mig discover components --all --write --file all-components
```

| Flag      | Type    | Effect                                                  |
| --------- | ------- | ------------------------------------------------------- |
| `--all`   | boolean | Discover all local and external component schema files. |
| `--write` | boolean | Write discovered component names to a local file.       |
| `--file`  | string  | Output file name when `--write` is passed.              |

Without `--write`, the command prints discovered component metadata. With
`--write`, it creates or overwrites the component list file.

### Migrations [#migrations]

```bash
sb-mig discover migrations --all
```

Prints discovered migration config filenames. This command is read-only.

## migrations recognize [#migrations-recognize]

```bash
sb-mig migrations recognize --from 3.4.0
sb-mig migrations recognize --from 3.4.0 --to 4.0.0
```

This command is specific to Backpack upgrade flows. It compares a previous
Backpack version with a target version and prints recommended `migrate content`
and `migrate presets` commands.

| Flag     | Type   | Effect                                                                                                                  |
| -------- | ------ | ----------------------------------------------------------------------------------------------------------------------- |
| `--from` | string | Previous package version. Required.                                                                                     |
| `--to`   | string | Target package version. Optional. Falls back to installed `@ef-global/backpack` dependency version from `package.json`. |

The command reads `applied-backpack-migrations.json` when present and reads
`package.json` when `--to` is omitted. It does not call Storyblok and does not
write files.

## init project [#init-project]

```bash
sb-mig init project \
  --spaceId 12345 \
  --oauthToken xxx \
  --region eu

sb-mig init project \
  --spaceId 12345 \
  --oauthToken xxx \
  --region us \
  --gtmToken GTM-XXXX
```

`init project` creates a local `.env` and updates the Storyblok space preview
domain.

| Flag           | Type                | Effect                                                                    |
| -------------- | ------------------- | ------------------------------------------------------------------------- |
| `--spaceId`    | string              | Storyblok space ID. Required.                                             |
| `--oauthToken` | string              | Management API OAuth token. Required.                                     |
| `--region`     | `eu`, `us`, or `cn` | Storyblok region. Required.                                               |
| `--gtmToken`   | string              | Optional Google Tag Manager token. Defaults to `put-your-gtm-token-here`. |

The generated `.env` includes region URLs, access token, OAuth token, preview
secret, space ID, translation strategy, and GTM ID. The preview domain is set to
`https://localhost:3000/api/preview/preview?secret=<secret>&slug=`.

## debug [#debug]

```bash
sb-mig debug
```

Prints resolved Storyblok config, `sb-mig` version, dependency versions, the
consumer `@ef-global/backpack` version when available, and whether the consumer
package is ESM or CommonJS. It reads local config and package metadata only.
