create
Insert a new record with auto-populated fields, nested relations, and type-safe returns.
Creates a new record in the database. Returns the created record, or null if the creation fails.
const user = await client.db.User.create({
data: {
email: 'jane@example.com',
name: 'Jane Doe',
isActive: true,
address: { street: '123 Main St', city: 'NYC', state: 'NY' },
nicknames: ['Jane'],
},
});
// user: UserOptions
| Option | Type | Required | Description |
|---|---|---|---|
data | UserCreateInput | Yes | The record data to insert |
select | UserSelect | No | Narrow which fields are returned |
Basic Usage
const post = await client.db.Post.create({
data: {
title: 'Hello World',
content: 'My first post',
},
});
// post: PostWith Select
Return only specific fields from the newly created record. The return type narrows to include only the selected fields:
const user = await client.db.User.create({
data: {
email: 'jane@example.com',
name: 'Jane',
isActive: true,
address: { street: '1 St', city: 'LA', state: 'CA' },
},
select: { id: true, email: true },
});
// user: { id: CerialId; email: string }Auto-Populated Fields
Several field types are automatically populated when you create a record. You don't need to include them in data — Cerial and SurrealDB handle them for you:
| Field Type | Behavior |
|---|---|
@id | SurrealDB auto-generates the record ID |
@createdAt | Set to the current timestamp at creation time (can be overridden) |
@updatedAt | Set to the current timestamp at creation and on every update |
@now | Computed at query time (not stored, cannot be set) |
@default(value) | Uses the default value if the field is not provided |
@uuid / @uuid4 / @uuid7 | Auto-generates a UUID if the field is not provided |
| Array fields | Default to [] if not provided |
| Optional object fields | Set to NONE (field absent) if not provided |
// Schema:
// model Post {
// id Record @id
// title String
// views Int @default(0)
// tags String[]
// createdAt Date @createdAt
// }
const post = await client.db.Post.create({
data: { title: 'Hello World' },
});
// post.id → CerialId (auto-generated)
// post.views → 0 (default applied)
// post.tags → [] (array default)
// post.createdAt → current timestamp (@createdAt)Nested Create
Create a related record inline within the parent create operation. The related record is created within the same transaction as the parent:
const post = await client.db.Post.create({
data: {
title: 'My Post',
author: {
create: {
name: 'John',
email: 'john@example.com',
isActive: true,
address: { street: '1 St', city: 'NYC', state: 'NY' },
},
},
},
});For array (one-to-many) relations, you can create multiple records at once:
const user = await client.db.User.create({
data: {
name: 'Jane',
email: 'jane@example.com',
isActive: true,
address: { street: '1 St', city: 'NYC', state: 'NY' },
posts: {
create: [{ title: 'Post 1' }, { title: 'Post 2' }],
},
},
});Connect to Existing Record
Link a new record to an existing related record by its ID:
const post = await client.db.Post.create({
data: {
title: 'My Post',
author: { connect: userId },
},
});The connect value accepts any RecordIdInput: a plain value, a CerialId, a RecordId, or a StringRecordId.
For array relations, connect multiple records at once:
const user = await client.db.User.create({
data: {
name: 'Jane',
email: 'jane@example.com',
isActive: true,
address: { street: '1 St', city: 'NYC', state: 'NY' },
posts: {
connect: [postId1, postId2],
},
},
});NONE vs null
How optional fields are handled on create depends on their schema modifiers (? and @nullable):
// field String? — optional only
{ bio: 'Hello' } // bio = 'Hello'
{ bio: undefined } // bio field NOT stored (NONE)
// { bio: null } // ❌ Error: bio is not nullable
// field String? @nullable — optional and nullable
{ bio: 'Hello' } // bio = 'Hello'
{ bio: undefined } // bio field NOT stored (NONE)
{ bio: null } // bio = null (explicit null stored in DB)
// field String? @nullable @default(null)
{ bio: undefined } // bio = null (default applied)
{ bio: null } // bio = null (explicit null)SurrealDB distinguishes absent fields (NONE) from null-valued fields. Use ? for fields that may be absent. Add @nullable when you need to store an explicit null. These are independent modifiers — a field can be optional, nullable, or both.
Passing null to a field that isn't decorated with @nullable is a validation error at runtime, even if the field is optional (?).
Return Value
- Returns the created record with all fields populated (including auto-generated and default values).
- When
selectis provided, only the selected fields are returned and the type narrows accordingly. - Returns
nullif the creation fails (e.g., unique constraint violation).
| Scenario | Return |
|---|---|
| No select | User |
| With select | { ...selected fields } |
| Creation fails | null |