---
url: /guide/importing.md
description: >-
  Move existing files in with media-library:import. Covers Spatie media, Curator
  and plain directories, options, dry runs and migration checklists.
---

# Importing

`media-library:import` copies existing files into the library. It reads three kinds of source: media managed by Spatie's laravel-medialibrary, rows from Awcodes Curator, and any folder on a disk.

```bash
php artisan media-library:import spatie --model="App\Models\Product" --collection=images --folder=Products

php artisan media-library:import curator --update=posts.featured_image_id --update=pages.hero_id --map=storage/curator-map.json

php artisan media-library:import directory uploads/legacy --disk=public --folder=Legacy
```

Every file goes through the same pipeline as a normal upload: type and size checks, SVG sanitising, conversions, the `MediaItemUploaded` event and, if enabled, queued alt text. Files that fail a check are skipped with a warning, and the rest continue.

## Options

| Option | Applies to | Meaning |
|---|---|---|
| `source` | all | `spatie`, `curator` or `directory`. |
| `path` | `directory` | Folder to import, relative to the disk root. |
| `--disk=` | `directory` | Disk to read from. Defaults to the library disk. |
| `--model=*` | `spatie` | Only media attached to these model classes. Repeat for several. |
| `--collection=*` | `spatie` | Only these Spatie collections. Repeat for several. |
| `--move` | `spatie` | Delete the original Spatie media after it is copied. |
| `--table=` | `curator` | Table holding the Curator rows. Defaults to `curator`. |
| `--update=*` | `curator` | A `table.column` whose values are rewritten to the new ids. Repeat for several. |
| `--folder=` | all | Put everything into this folder, created when missing. |
| `--map=` | all | Write a JSON map of old id to new library id to this file. |
| `--tenant=` | all | Tenant key to assign to the imported records. |
| `--tenant-model=` | all | Tenant model class. Required with `--tenant`. |
| `--dry-run` | all | Count what would be imported and write nothing. |

## Spatie media

```bash
php artisan media-library:import spatie
```

This copies every Spatie media row that does not already belong to the library, then attaches the new library item back to the model that owned it, in the same collection. Usage tracking works straight away, and `$product->getMediaLibraryItems('images')` returns the files once the model uses [`HasMediaLibrary`](/guide/models-and-blade).

* The item name comes from the media name. `alt` and `caption` are read from the media's custom properties.
* Without `--folder`, files go into `Imported/<ModelName>`, for example `Imported/Product`.
* The originals stay in place unless you pass `--move`, which deletes each Spatie media row and its file after it was copied.

## Curator

```bash
php artisan media-library:import curator --update=posts.featured_image_id
```

This reads the `curator` table (change it with `--table`) and copies each file from its `disk` and `path`. Title, alt text, caption and description come across when the row has them. Without `--folder`, files go into `Imported/Curator`.

`--update=table.column` rewrites every value in that column from the old Curator id to the new library id, in one query per 500 ids. Pass it once for each column that stores a Curator id. A column that does not exist is skipped with a warning.

::: warning
`--update` replaces values by looking up old ids. If you run it a second time, values that were already rewritten can match an old id and be changed again. Back up the database first and run the rewrite once. Rows whose file failed to import keep their old id.
:::

## Directory

```bash
php artisan media-library:import directory uploads/legacy --disk=public --folder=Legacy
```

This imports every file under the path. Sub directories become folders, nested under `--folder` when you give one. Files starting with a dot are ignored. Files are copied, so the originals are left alone.

## Dry runs

```bash
php artisan media-library:import spatie --dry-run -v
```

A dry run creates no files, no folders and no map file. It prints `Would import N files, skipped M.` Add `-v` to list each file. Already imported files count as skipped.

## Safe to run again

Each imported item records where it came from in its custom properties (`imported_from`, such as `spatie:12`, `curator:100` or `directory:public:uploads/legacy/a.png`). A second run skips files it has already imported, even if they are in the trash, so an interrupted import can continue where it stopped.

## What to know

* Imported files are shared and have no uploader, because the command runs without a signed-in user. They appear under **All media**, not under **My uploads**.
* Thumbnails are built during the import. Larger conversions are queued, so run a worker: see [Storage](/guide/storage).
* Duplicate detection is not applied. Two copies of the same file in the source become two items.
* With tenancy on, pass `--tenant` and `--tenant-model` so the records land in the right tenant. See [Tenancy](/guide/tenancy).

## Checklist: from Curator

1. Back up the database and the storage disk.
2. Install the package and run its migrations: see [Installation](/guide/installation).
3. List every column that holds a Curator id, for example `posts.featured_image_id`.
4. Run `media-library:import curator --dry-run -v` and check the count.
5. Run the import with one `--update` for each column, and `--map=storage/curator-map.json`.
6. Read the warnings. Fix anything that was skipped, then handle those ids by hand with the map.
7. Replace Curator fields in your resources with [`MediaPicker`](/guide/picker-field), using the same column names, and Curator display columns with [`MediaColumn`](/guide/table-columns).
8. For columns that store several ids as JSON, rewrite them yourself using the map file. `--update` only handles one id per cell.
9. Start a queue worker, open the library and spot check files and alt text.
10. Remove Curator once nothing references it.

## Checklist: from a plain Spatie setup

1. Back up the database and the storage disk.
2. Install the package and run its migrations.
3. Add `HasMediaLibrary` to the models whose media you are importing.
4. Run `media-library:import spatie --dry-run -v`, narrowing with `--model` and `--collection` if needed.
5. Run the import without `--move`, so your original Spatie media stays until you have checked the result.
6. Switch reads from `$model->getMedia('images')` to `$model->getMediaLibraryItems('images')`, and forms to [`MediaPicker`](/guide/picker-field) with `relationship('images')`.
7. Compare counts per model and collection, then check the pages that show the images.
8. Remove the old Spatie media yourself when you are happy. `--move` only deletes originals as they are copied, so a second run with `--move` does not delete files that an earlier run already imported.
