---
title: "Import & export — Options for Laravel | Roundly"
description: "Move options between environments or seed defaults with Options::export(), exportJson() and import() — or the matching Artisan commands."
url: https://roundly-consulting.com/open-source/docs/options-for-laravel/import-export
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Options for Laravel](https://roundly-consulting.com/open-source/docs/options-for-laravel.md)

# Import & export

Move options between environments or ship seeded defaults through the facade (or an injected OptionsManager). options:export and options:import call the same manager, and ExportOptionsAction / ImportOptionsAction do the work underneath (see DI and actions):

```php
use RoundlyConsulting\Options\Facades\Options;

Options::export();                   // list<OptionPayload>: every stored option, global and owned
Options::export($tenant);            // one owner's options
Options::export(globalOnly: true);   // only the global ones
Options::for($tenant)->export();     // one scope; Options::for(null)->export() = global only

$json = Options::exportJson($tenant); // the same, as a JSON array of rows

$count = Options::import($json);                                   // JSON string — upsert, returns the count
$count = Options::import([['key' => 'theme', 'value' => 'dark']]); // decoded rows (owner_type / owner_id optional)
$count = Options::import($payloads);                               // list<OptionPayload>; rows and payloads may be mixed
```

## Payload format

exportJson() and options:export produce a JSON array of OptionPayload rows:

```json
[
  { "key": "theme", "value": "dark", "owner_type": null, "owner_id": null },
  { "key": "theme", "value": "light", "owner_type": "App\\Models\\User", "owner_id": 5 }
]
```

## Behaviour

- Values travel exactly as stored — serialized, and still encrypted for encrypted options, so the target app needs the same APP\_KEY to read them.
- Import upserts on key, owner\_type and owner\_id, so re-importing the same file is idempotent. A forgotten option’s soft-deleted row is revived rather than duplicated.
- Import writes rows directly: no rules() validation, casts, events or observers.
- An import is all or nothing: every value is checked before the first row is written, and the rows are written in one transaction, so a failure part-way through leaves no row imported.
- import() returns the number of rows, and each imported value is cached as a write caches it, so the next read — in this request or any other — sees it.
- owner\_id follows options.key\_type — an int for bigint owners, a string for UUID or ULID owners. A row with only one of owner\_type / owner\_id is imported as global.
- Malformed JSON, a JSON scalar, a non-array row, a row without a string key or a value that isn’t a string, number, boolean or null throws InvalidOptionPayload and imports nothing. A value is stored as its column string: 30 becomes “30”, true becomes “1”.
- With access control on, an export leaves out what the current user may not read, and an import refuses any row the user may not write or whose key no registered option answers for — UnauthorizedOption, nothing imported. options:export and options:import bypass enforcement, like every console command.
- Under Options::fake(), export() and exportJson() read the in-memory store — which holds what the database would: raw strings, ciphertext for an encrypted option — and import() is recorded (assertImported()) and loaded into it, refusing the same input as the real one.

## From the command line

```bash
php artisan options:export --path=storage/options.json
php artisan options:export --owner="App\Models\User" --owner-id=5

php artisan options:import storage/options.json
php artisan options:clear-cache
```

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/options-for-laravel.md)
