Cerial
Queries

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: User

Options

OptionTypeRequiredDescription
dataUserCreateInputYesThe record data to insert
selectUserSelectNoNarrow which fields are returned

Basic Usage

const post = await client.db.Post.create({
  data: {
    title: 'Hello World',
    content: 'My first post',
  },
});
// post: Post

With 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 TypeBehavior
@idSurrealDB auto-generates the record ID
@createdAtSet to the current timestamp at creation time (can be overridden)
@updatedAtSet to the current timestamp at creation and on every update
@nowComputed at query time (not stored, cannot be set)
@default(value)Uses the default value if the field is not provided
@uuid / @uuid4 / @uuid7Auto-generates a UUID if the field is not provided
Array fieldsDefault to [] if not provided
Optional object fieldsSet 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 select is provided, only the selected fields are returned and the type narrows accordingly.
  • Returns null if the creation fails (e.g., unique constraint violation).
ScenarioReturn
No selectUser
With select{ ...selected fields }
Creation failsnull

On this page