> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erdo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Write dataset rows

> Append, replace, or merge JSON rows in a dataset from the CLI.

`erdo datasets write` appends or updates rows in an existing writable dataset.
The examples below use an ordinary file dataset. Pass `--org` and `--project`
when you need to select the workspace and project explicitly.

A populated canonical lead dataset refuses generic row writes. Use its capture
pipeline or the supported [lead identity operations](/lead-identity.md).

## Append rows

Pass a JSON array inline or load it from a file with `@`:

```bash theme={null}
erdo datasets write acme.contacts \
  --rows '[{"email":"ada@example.com","name":"Ada"}]'

erdo datasets write acme.contacts --rows @rows.json
```

Each array element must be a non-null JSON object. The CLI sends its JSON values
unchanged; storage behavior depends on the dataset. File datasets store cell
values as text, with JSON null becoming an empty cell. Objects and arrays do not
round-trip as JSON: for example, an object may become `map[plan:pro]`. If a file
dataset column needs JSON that can be parsed later, supply an encoded JSON
string, such as `"meta": "{\"plan\":\"pro\"}"`. An empty array is a
successful zero-row no-op.

## Replace matching rows

Add a key column to upsert by that value:

```bash theme={null}
erdo datasets write acme.contacts \
  --rows @contact-update.json \
  --key-column email
```

Omit both `--key-column` and `--write-mode` to append. With a key, new keys insert
and matching keys update. File datasets replace the matching row, clearing fields
omitted from the incoming row. PostgreSQL tables update the non-key columns
present in the batch. Columns absent from every row stay unchanged; omitting a
column supplied by another row writes `NULL` for that cell. `--write-mode replace` selects this default
explicitly and requires a non-blank `--key-column`, just like merge mode. A
supplied key must name at least one non-blank column, even when the write mode
is omitted. A comma-separated value supplies a composite key:

```bash theme={null}
erdo datasets write acme.daily-metrics \
  --rows @metrics.json --key-column date,page_uuid
```

Replacement changes matching rows and preserves unrelated rows in the dataset.
It does not replace the whole dataset. File datasets and writable PostgreSQL
tables support this keyed replacement. ClickHouse-backed writes append even
when `--key-column` is supplied with the default or explicit
`--write-mode replace`; they do not update the matching row.

## Merge matching rows

Merge mode requires a non-blank key. It fills blank fields and preserves
existing non-blank values:

```bash theme={null}
erdo datasets write acme.contacts \
  --rows '[{"email":"ada@example.com","company":"Acme"}]' \
  --key-column email --write-mode merge
```

Use `--overwrite-columns` when selected non-blank incoming values should also
replace existing values:

```bash theme={null}
erdo datasets write acme.contacts \
  --rows @contact-update.json --key-column email \
  --write-mode merge --overwrite-columns company,title
```

`--overwrite-columns` is valid only with merge mode and cannot contain empty
column names. The server also refuses attempts to overwrite a key column.
Storage support varies: file datasets and writable PostgreSQL tables support
merge; ClickHouse-backed datasets refuse merge mode.

## Response and errors

The command prints the server's JSON count response:

```json theme={null}
{
  "rows_affected": 1,
  "rows_inserted": 0,
  "rows_updated": 1
}
```

Writes require edit access to the dataset. The dataset's declared columns and
required fields still apply; the server reports contract and storage errors.
For a file merge, required fields are checked on the resulting row, so a partial
update can retain required values already stored. The CLI does not automatically
retry a row write after a network failure: the request may have reached the server,
so inspect the affected dataset before retrying manually.

## Repair dataset user access

An organization operator can inspect and repair explicit dataset user grants
without bypassing RBAC:

```bash theme={null}
erdo datasets permissions list acme.contacts --json
erdo datasets permissions set-user acme.contacts USER_UUID --level edit --json
erdo datasets permissions remove-user acme.contacts USER_UUID --json
```

These endpoints require an organization member session or full organization API key, and an admin or owner
grant on the exact dataset. The list and set responses contain only `user_id`
and `level`; they do not expose email addresses. Removal verifies that the
direct grant is absent on readback; it does not assert that all effective access was revoked. A user may still have access through an
organization or another inherited grant after a direct grant is removed.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.