Running a query from the CLI and outputting it as a .ndjson file in Sanity.io

3 replies
Last updated: Feb 14, 2024
Hi, is it possible from the cli to run a query, and output it as a
.ndjson
file? Not just json.
pnpm -F studio exec sanity documents query --dataset archive '*[_type == "event"]{..., "tags": [], "fromArchive": true }[0..1]' > ./apps/studio/exports/archived-events.ndjson <<<<<
My use case is that I want to query some documents from an "archive" dataset, and then import then into another dataset.
But the dataset import only takes ndjson, while the query only outputs json.
AI Update

Unfortunately, sanity documents query outputs standard JSON (an array), not NDJSON format. However, you can easily work around this to achieve your goal of querying from one dataset and importing to another.

The Problem

The sanity documents query command outputs JSON as an array of results, while sanity dataset import requires NDJSON (newline-delimited JSON where each document is on its own line).

Solutions

You can pipe the query output through jq to convert it to NDJSON format:

pnpm -F studio exec sanity documents query \
  --dataset archive \
  '*[_type == "event"]{..., "tags": [], "fromArchive": true}' \
  | jq -c '.[]' > ./apps/studio/exports/archived-events.ndjson

The jq -c '.[]' command:

  • .[] iterates over each element in the JSON array
  • -c outputs compact JSON (one line per document)

Then import it to your target dataset:

pnpm -F studio exec sanity dataset import \
  ./apps/studio/exports/archived-events.ndjson \
  production

Option 2: Use sanity dataset export with Post-Processing

If your filtering needs are complex, you could export the entire dataset and then filter:

# Export the archive dataset
sanity dataset export archive archive-export.tar.gz

# Extract, filter the NDJSON, then import
sanity dataset import filtered-events.ndjson production

This approach works well when you need to transform documents beyond what GROQ queries can do.

Option 3: Use a Custom Script with sanity exec

For maximum control, create a migration script using sanity exec:

// scripts/migrate-from-archive.js
import {getCliClient} from 'sanity/cli'
import {createWriteStream} from 'fs'

const client = getCliClient()
const archiveClient = client.withConfig({dataset: 'archive'})

const query = '*[_type == "event"]{..., "tags": [], "fromArchive": true}'
const docs = await archiveClient.fetch(query)

const writeStream = createWriteStream('./exports/archived-events.ndjson')
docs.forEach(doc => {
  writeStream.write(JSON.stringify(doc) + '\n')
})
writeStream.end()

Run it with:

sanity exec scripts/migrate-from-archive.js --with-user-token

Use Option 1 with jq - it's the simplest and most direct solution. The jq tool is widely available on most systems (or easily installable via package managers like brew install jq on macOS or apt-get install jq on Ubuntu) and is perfect for this JSON-to-NDJSON conversion task.

The key insight is that sanity documents query returns a JSON array, so you just need to unwrap that array into individual lines - which is exactly what jq -c '.[]' does.

I would like to do it all with cli, so I don't have to run scripts.
Found this great one-liner:
cat test.json | jq -c '.[]' > testNDJSON.json

Yep, that’s what I use as well.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?