flexkit import
Imports entities and assets in bulk from an NDJSON file, a directory or a tarball created by flexkit export. Referenced files are uploaded first and connected to entities by _id, so a single import file can describe a full dataset — including images and entity relationships.
Synopsis
flexkit import <file.ndjson | dir | tarball> [options]Accepted inputs
- NDJSON file — one entity per line. Relative file references resolve against the file’s directory.
- Directory — must contain a
data.ndjson(entities) and/or anassets.ndjson(asset metadata) with the referenced files alongside. - Tarball (
.tar.gz,.tgz,.tar) — same layout as a directory; this is whatflexkit exportandflexkit assets exportproduce.
Import file format
Each line of data.ndjson is a JSON object describing one entity:
{
"_type": "product",
"_id": "product-chair",
"name": "Chair",
"description": "A red chair",
"image": { "_asset": "file://images/chair.jpg" },
"gallery": [{ "_asset": "https://example.com/detail.jpg" }],
"brand": { "_ref": "brand-acme" }
}_type(required): the entity name (or plural) as defined in your schema._id(optional): a stable id for the entity. Omitting it generates a random UUID — but supplying deterministic ids is strongly recommended, since they make re-runs idempotent and enable_refrelationships.- Scalar attributes (global scope): plain JSON values.
- Localized attributes (
scope: 'local'): a plain JSON value writes thedefaultscope. To set several scopes, use{"_scopes": {"default": "Chair", "gb": "Armchair"}}— one entry per scope name defined in the project’sscopesconfig. Unknown scope names fail validation. - Asset attributes (
dataType: 'asset'):{"_asset": "<source>"}where the source is afile://path (relative to the NDJSON file), a plain relative path, or anhttps://URL. - Asset relationships (relationship to
_asset, multiple mode): an array of{"_asset": ...}values. Array position becomes thesortOrderof each connection. - Entity relationships:
{"_ref": "<entity _id>"}(single mode) or an array of refs (multiple mode). Refs may point at entities defined later in the same file — they are connected in a second pass after all entities exist.
Unknown types or attributes fail validation before anything is written.
Pipeline
- Parse and validate every line against the local config’s schema; verify referenced local files exist. Any error aborts the import before uploads or mutations run.
- Upload assets — each unique source is uploaded once through the one-shot assets endpoint. SHA-256 deduplication means re-importing the same files never creates duplicates.
- Create entities in batches using GraphQL variables (no string interpolation). If a batch fails, its items retry one-by-one so a single conflict doesn’t sink the batch. Asset connections are made inline by
_id. - Connect
_refrelationships in a second pass, so forward references between lines are fine.
Idempotency and re-runs
- Assets are deduplicated by content hash — re-runs upload nothing new.
- Entities with an
_idthat already exists are skipped by default (--skip-existing). - With
--replace, existing entities are updated instead: scalar values are set (for localized attributes, only the scopes present in the file are touched), and asset/relationship connections are diffed against the current state (removed connections are disconnected, new ones connected, order updated).
Options
--project <ID>: Select the project when the local config defines several.--dry-run: Validate the input and report what would happen. Nothing is uploaded or created.--skip-existing: Skip entities whose_idalready exists (default).--replace: Update entities whose_idalready exists instead of skipping them.--batch-size <N>: Entities per create mutation (default10).--concurrency <N>: Parallel asset uploads (default5).--tag <NAME>: Tag every imported asset with the given tag.--json: Print the import summary as JSON on stdout.
The command exits non-zero if any entity or asset failed, and prints a created / replaced / skipped / failed summary.
Worked example: products with images
products.ndjson:
{"_type": "brand", "_id": "brand-acme", "name": "Acme"}
{"_type": "product", "_id": "product-chair", "name": "Chair", "image": {"_asset": "file://images/chair.jpg"}, "gallery": [{"_asset": "file://images/chair-front.jpg"}, {"_asset": "file://images/chair-side.jpg"}], "brand": {"_ref": "brand-acme"}}
{"_type": "product", "_id": "product-table", "name": "Table", "image": {"_asset": "https://example.com/table.jpg"}, "brand": {"_ref": "brand-acme"}}# Validate first
flexkit import products.ndjson --dry-run
# Import (images upload first, then entities, then relationships)
flexkit import products.ndjson
# Re-run safely: assets dedupe, existing entities are skipped
flexkit import products.ndjson
# Update existing entities with changed values instead
flexkit import products.ndjson --replaceLast updated on