# InsertPromise

InsertPromise provides chainable methods for configuring INSERT operations.

The `InsertPromise` class provides a chainable interface for configuring INSERT operations for bulk record insertion. It extends `Promise`, allowing you to `await` it directly or chain configuration methods.

**Returned by:** [`SurrealQueryable.insert()`](/docs/reference/javascript/api/core/surreal-queryable.md#insert)

**Source:** [query/insert.ts](https://github.com/surrealdb/surrealdb.js/blob/main/packages/sdk/src/query/insert.ts)

## Type parameters

- `T` - The result type
- `J` - Boolean indicating if result is JSON (default: `false`)

## Configuration methods

### `.relation()` {#relation}

Configure the insert to work with relation (edge) records instead of regular records.

```ts title="Method Syntax"
insertPromise.relation()
```

#### Returns
`InsertPromise<T, J>` - Chainable promise

#### Example

```ts
const edges = await db.insert([
    {
        id: new RecordId('likes', '1'),
        in: new RecordId('users', 'john'),
        out: new RecordId('posts', '1')
    }
]).relation();
```

---

### `.ignore()` {#ignore}

Ignore records that already exist (skip duplicates without error).

```ts title="Method Syntax"
insertPromise.ignore()
```

#### Returns
`InsertPromise<T, J>` - Chainable promise

#### Example

```ts
const users = await db.insert([
    { id: new RecordId('users', 'john'), name: 'John' },
    { id: new RecordId('users', 'jane'), name: 'Jane' }
]).ignore();
// If 'john' exists, it's skipped; 'jane' is inserted
```

---

### `.output()` {#output}

Specify which fields to return in the response.

```ts title="Method Syntax"
insertPromise.output(fields)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>fields</code> <label label="required" /></td>
            <td><code>Output</code></td>
            <td><code>"NONE"</code>, <code>"AFTER"</code>, or specific field list.</td>
        </tr>
    </tbody>
</table>

#### Returns
`InsertPromise<T, J>` - Chainable promise

#### Examples

```ts title="Return Specific Fields"
const users = await db.insert(userData)
    .output('id', 'name');
// Returns only id and name
```

```ts title="Return Nothing"
await db.insert(logData)
    .output('NONE');
// No return value, useful for performance
```

---

### `.timeout()` {#timeout}

Set a timeout for the operation.

```ts title="Method Syntax"
insertPromise.timeout(duration)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>duration</code> <label label="required" /></td>
            <td><code><a href="/docs/reference/javascript/api/values/duration.md">Duration</a></code></td>
            <td>Maximum time to wait.</td>
        </tr>
    </tbody>
</table>

#### Returns
`InsertPromise<T, J>` - Chainable promise

---

### `.version()` {#version}

Insert at a specific version (for versioned storage engines).

```ts title="Method Syntax"
insertPromise.version(timestamp)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>timestamp</code> <label label="required" /></td>
            <td><code><a href="/docs/reference/javascript/api/values/datetime.md">DateTime</a></code></td>
            <td>The version timestamp.</td>
        </tr>
    </tbody>
</table>

#### Returns
`InsertPromise<T, J>` - Chainable promise

---

### `.retry()` {#retry}

Retry the operation with exponential backoff if it fails due to a write conflict. Off by default; passing an options object (or calling with no arguments) opts the operation in.

This overrides the connection-wide default set via the [`retry`](/docs/reference/javascript/api/types/#connectoptions) option on `ConnectOptions`.

```ts title="Method Syntax"
insertPromise.retry(options?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>options</code> <label label="optional" /></td>
            <td><code>Partial&lt;<a href="/docs/reference/javascript/api/types/#retryoptions">RetryOptions</a>&gt;</code></td>
            <td>Retry configuration. If omitted, retry is enabled with the default configuration.</td>
        </tr>
    </tbody>
</table>

#### Returns
`InsertPromise<T, J>` - Chainable promise

#### Example

```ts
await db.insert(new Table('users')).content(users).retry({ attempts: 3 });
```

---

### `.json()` {#json}

Return result as JSON string.

```ts title="Method Syntax"
insertPromise.json()
```

#### Returns
`InsertPromise<T, true>` - Promise returning JSON string

---

### `.compile()` {#compile}

Compile the query into a `BoundQuery` without executing it.

```ts title="Method Syntax"
insertPromise.compile()
```

#### Returns
`BoundQuery<[T]>` - The compiled query

#### Example

```ts
const query = db.insert(records)
    .compile();
```

---

### `.stream()` {#stream}

Stream results as records are inserted.

```ts title="Method Syntax"
insertPromise.stream()
```

#### Returns
`AsyncIterableIterator` - Async iterator

## Complete examples

### Basic insertion

```ts
import { Surreal, RecordId } from 'surrealdb';

const db = new Surreal();
await db.connect('ws://localhost:8000');

// Insert single record
const user = await db.insert({
    id: new RecordId('users', 'alice'),
    name: 'Alice',
    email: 'alice@example.com'
});

// Insert multiple records
const users = await db.insert([
    { id: new RecordId('users', 'bob'), name: 'Bob' },
    { id: new RecordId('users', 'carol'), name: 'Carol' }
]);
```

### Insert into table

```ts
// Let database generate IDs
const users = await db.insert(new Table('users'), [
    { name: 'Dave', email: 'dave@example.com' },
    { name: 'Eve', email: 'eve@example.com' }
]);
```

### Insert a record link

A field typed as a record link needs a [`RecordId`](/docs/reference/javascript/api/values/record-id.md) instance, built from the table name and the id as separate arguments. A string that looks like a record ID stays a string, so the insert fails with `Expected record<company> but found 'company:acme'`.

```ts
import { RecordId, Table } from 'surrealdb';

// Schema: DEFINE FIELD company ON job TYPE record<company>;
await db.insert(new Table('job'), {
    description: 'Hello World',
    company: new RecordId('company', 'acme')
});
```

Where the id arrives as a single string, convert it inside the query with [`type::record()`](/docs/reference/query-language/functions/database-functions/type.md#typerecord) instead:

```ts
await db.query(
    'INSERT INTO job { description: $description, company: type::record($company) }',
    { description: 'Hello World', company: 'company:acme' }
);
```

### Ignore duplicates

```ts
// Skip existing records without error
const users = await db.insert([
    { id: new RecordId('users', 'john'), name: 'John' },
    { id: new RecordId('users', 'jane'), name: 'Jane' }
]).ignore();

console.log(`Inserted ${users.length} new users`);
```

### Bulk insert with streaming

```ts
const largeDataset = generateThousandsOfRecords();

let count = 0;
for await (const record of db.insert(largeDataset).stream()) {
    count++;
    if (count % 100 === 0) {
        console.log(`Inserted ${count} records`);
    }
}
```

### Insert relations (edges)

```ts
const likes = await db.insert([
    {
        id: new RecordId('likes', '1'),
        in: new RecordId('users', 'john'),
        out: new RecordId('posts', '1'),
        created_at: DateTime.now()
    },
    {
        id: new RecordId('likes', '2'),
        in: new RecordId('users', 'jane'),
        out: new RecordId('posts', '1'),
        created_at: DateTime.now()
    }
]).relation();
```

### Optimised insertion

```ts
// Don't wait for return values
await db.insert(logEntries)
    .output('NONE');
// Faster execution when you don't need the results
```

### Insert with timeout

```ts
const users = await db.insert(largeDataset)
    .timeout(Duration.parse('30s'));
```

### Error handling

```ts
try {
    const users = await db.insert([
        { id: new RecordId('users', 'existing'), name: 'Test' }
    ]);
} catch (error) {
    if (error instanceof ResponseError) {
        console.error('Duplicate key error:', error.message);
        
        // Retry with ignore
        const users = await db.insert([
            { id: new RecordId('users', 'existing'), name: 'Test' }
        ]).ignore();
    }
}
```

### Batch processing

```ts
const BATCH_SIZE = 100;
const allUsers = [...]; // Large array

for (let i = 0; i < allUsers.length; i += BATCH_SIZE) {
    const batch = allUsers.slice(i, i + BATCH_SIZE);
    await db.insert(batch);
    console.log(`Inserted batch ${i / BATCH_SIZE + 1}`);
}
```

## INSERT vs CREATE

### When to use INSERT vs CREATE

```ts
// CREATE: For single records, with more configuration options
const user = await db.create(new RecordId('users', 'john'))
    .content(userData);

// INSERT: For bulk operations, optimized for performance
const users = await db.insert([
    { id: new RecordId('users', 'alice'), ...data1 },
    { id: new RecordId('users', 'bob'), ...data2 },
    { id: new RecordId('users', 'carol'), ...data3 }
]);
```

## Chaining pattern

```ts
const result = await db.insert(records)
    .ignore()
    .output('id', 'name')
    .timeout(Duration.parse('10s'));
```

## See also

- [SurrealQueryable.insert()](/docs/reference/javascript/api/core/surreal-queryable.md#insert) - Method that returns InsertPromise
- [CreatePromise](/docs/reference/javascript/api/queries/create-promise.md) - Single record creation
- [UpsertPromise](/docs/reference/javascript/api/queries/upsert-promise.md) - Insert or update
- [Query overview](/docs/reference/javascript/api/queries/) - All query builder classes
