---
title: "Define fields, constraints and assertions | SurrealDB University"
description: "Define fields, constraints and assertions. A chapter of SurrealDB Fundamentals, a hands-on course with runnable examples."
url: https://surrealdb.com/learn/fundamentals/schemafull/define-fields
---

[Back to Courses](https://surrealdb.com/learn)

Course chapters

[SurrealDB Fundamentals](https://surrealdb.com/learn/fundamentals) [Introduction](https://surrealdb.com/learn/fundamentals) [Welcome to SurrealDB University](https://surrealdb.com/learn/fundamentals/intro/welcome) [Intro to SurrealDB](https://surrealdb.com/learn/fundamentals/intro/surrealdb) [Why SurrealQL is SQL-like](https://surrealdb.com/learn/fundamentals/intro/surrealql) [Part 1: Schemaless CRUD](https://surrealdb.com/learn/fundamentals/schemaless) [Introduction](https://surrealdb.com/learn/fundamentals/schemaless) [Record IDs](https://surrealdb.com/learn/fundamentals/schemaless/record-ids) [Inserting data](https://surrealdb.com/learn/fundamentals/schemaless/inserting-data) [Reading data](https://surrealdb.com/learn/fundamentals/schemaless/reading-data) [Updating data](https://surrealdb.com/learn/fundamentals/schemaless/updating-data) [Deleting data](https://surrealdb.com/learn/fundamentals/schemaless/deleting-data) [Part 2: Adding relationships](https://surrealdb.com/learn/fundamentals/relationships) [Introduction](https://surrealdb.com/learn/fundamentals/relationships) [Graph relations](https://surrealdb.com/learn/fundamentals/relationships/graph-relations) [Record links](https://surrealdb.com/learn/fundamentals/relationships/record-links) [Relational style joins](https://surrealdb.com/learn/fundamentals/relationships/relational-style) [Part 3: Making it schemafull](https://surrealdb.com/learn/fundamentals/schemafull) [Introduction](https://surrealdb.com/learn/fundamentals/schemafull) [Define tables, views and changefeeds](https://surrealdb.com/learn/fundamentals/schemafull/define-table) [Define fields, constraints and assertions](https://surrealdb.com/learn/fundamentals/schemafull/define-fields) [Schemafull CRUD](https://surrealdb.com/learn/fundamentals/schemafull/schemafull-crud) [Part 4: Making it secure](https://surrealdb.com/learn/fundamentals/security) [Introduction](https://surrealdb.com/learn/fundamentals/security) [Authentication](https://surrealdb.com/learn/fundamentals/security/authentication) [Query capabilities](https://surrealdb.com/learn/fundamentals/security/query-capabilities) [Part 5: Making it performant](https://surrealdb.com/learn/fundamentals/performance) [Introduction](https://surrealdb.com/learn/fundamentals/performance) [Indexing & data model considerations](https://surrealdb.com/learn/fundamentals/performance/index-data-model) [Deployment & storage layer considerations](https://surrealdb.com/learn/fundamentals/performance/deployment-storage) [Completion](https://surrealdb.com/learn/fundamentals/completion) Certification Pending completion

# Define fields, constraints and assertions

Now that we've defined our tables, it's time to also define our fields.

In this lesson, we'll cover how to:

- Define fields and their various data types
- Add field constraints and assertions
- Add permissions to field definitions

## Defining fields

The way fields are defined is similar to how we define tables.

```
DEFINE FIELD product_name ON TABLE order;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

We use the `DEFINE FIELD` statement to, at a minimum, specify the field name and which table it belongs to, but usually also the `TYPE` as well. If the `TYPE` is not specified, it will default to `TYPE any`, which allows it to be set to any value.

The important thing to note is that the `DEFINE FIELD` statement can be used independently from the `DEFINE TABLE` statement, which is why we must always specify which table it belongs to using the `ON TABLE` clause.

## Data types

```
DEFINE FIELD product_name    ON TABLE order    TYPE string;DEFINE FIELD quantity    ON TABLE order    TYPE number;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

Defining simple data types is very straightforward, we just use the `TYPE` clause and the name of the data type, such as a string or number.

SurrealDB supports various datatypes, all of which you can find listed in our [documentation](https://surrealdb.com/docs/reference/query-language/language-primitives/data-types).

Complex data types, as the name suggests, are not as straightforward, let's therefore spend some time looking at various examples. In particular nested objects and arrays.

### Objects

```
DEFINE FIELD time    ON TABLE product    TYPE object;DEFINE FIELD time.created_at    ON TABLE product    TYPE datetime;DEFINE FIELD time.updated_at    ON TABLE product    TYPE datetime;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

Starting with objects, let's take the example of a field called `time` which is an object containing the `created_at` and `updated_at` fields.

- First, we define the `time` field as `TYPE object`
- Then we use the dot notation to define the fields inside the object separately.

In this case, we define both `time.created_at` and `time.updated_at` as a `TYPE datetime`.

Regardless of how nested the object is, we just use the dot notation to define each nested field, one at a time.

### Arrays and an arrays of objects

To define the contents of an array of strings there are two options:

- Using `TYPE array` with the string data type in angle brackets
- Using just `TYPE array` for the `sizes` field, then defining the contents using `.*`

```
DEFINE FIELD sizes    ON TABLE product    TYPE array<string>;DEFINE FIELD IF NOT EXISTS sizes    ON TABLE product    TYPE array;DEFINE FIELD IF NOT EXISTS sizes.*    ON TABLE product    TYPE string;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

When defining arrays of objects such as this `addresses` array on the `address_history` table, you can use one of two approaches:

- Since `addresses.*` means all the address objects, use the dot notation again to define each nested field, such as `addresses.*.address_line_1`.
- Insert the field and type names directly into object notation. This is less wordy so will be the approach we will use.

```
DEFINE FIELD addresses    ON TABLE address_history    TYPE array<{        address_line_1: string,        address_line_2: option<string>,        city: string,        coordinates: geometry<point>,        country: string,        post_code: string    }>;-- The first approach:-- DEFINE FIELD addresses.*.address_line_1--     ON TABLE address_history--     TYPE string;-- DEFINE FIELD addresses.*.address_line_2--     ON TABLE address_history--     TYPE option<string>;-- DEFINE FIELD addresses.*.city--     ON TABLE address_history--     TYPE string;-- DEFINE FIELD addresses.*.coordinates--     ON TABLE address_history--     TYPE geometry<point>;-- DEFINE FIELD addresses.*.country--     ON TABLE address_history--     TYPE string;-- DEFINE FIELD addresses.*.post_code--     ON TABLE address_history--     TYPE string;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

### Cheat code - flexible type

There is however an easy cheat code for nested objects and arrays when you do not want to apply a strict schema on every field.

```
DEFINE TABLE lesson SCHEMAFULL;DEFINE FIELD summary    ON TABLE lesson    TYPE object FLEXIBLE;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

The `FLEXIBLE` clause allows us to have schemaless fields on schemafull tables. This is especially useful for fields containing nested objects such as `shipping_address`, where the address structure can be very different based on the country we are shipping to.

```
DEFINE FIELD addresses    ON TABLE address_history    TYPE array<object> FLEXIBLE;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

The field type is still `array<object>`. `FLEXIBLE` applies to each object in the array, so you can simplify `addresses` without defining every nested path.

### Record and option type

We can also define record IDs, using `TYPE record` with the table name of one or more records in angle brackets, such as the `TYPE record<seller>` field on the `product` table.

```
DEFINE FIELD seller     ON TABLE product     TYPE record<seller>;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

Finally, we can use the option type to allow a field to either be empty or have the specified data type. As an example, using `TYPE option<datetime>` on the `time.shipped_at` field will allow it to be empty until the order is shipped.

## Constraints and assertions

```
DEFINE FIELD email    ON TABLE person    TYPE string    ASSERT string::is_email($value);DEFINE FIELD rating    ON TABLE review    TYPE number    ASSERT $value > 0 AND $value < 6;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

We can take our field definitions even further by using assertions. The `ASSERT` clause can be used to ensure that our data remains consistent.

For example:

- We can use assertions to ensure that the `email` field on our `person` table is always a valid email address.
- We can also ensure that the `rating` field on our `review` table is always a number greater than 0 and less than 6.

To do this we use the `$value` parameter as a placeholder for the field value. Assertions can be simple, but also contain complex logic.

### Default field values

The `DEFINE FIELD` statement has two clauses for setting a default value for our fields, `DEFAULT` and `VALUE`.

```
DEFINE FIELD time.created_at    ON TABLE person    TYPE datetime    DEFAULT time::now();DEFINE FIELD time.updated_at    ON TABLE person    TYPE datetime    VALUE time::now();
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

The most practical way to explain the difference between them is:

- `DEFAULT` is better used for fields like `time.created_at` as the `DEFAULT time::now()` will be static once used for the first time.
- `VALUE` is better used for fields like `time.updated_at` because `VALUE time::now()` will run every time the record is updated.

In this way, we never again need to remember to use `time.created_at` or `time.updated_at` in our queries, as it will be created and updated for us when we insert a record into the table.

```
CREATE person:01FS8RCP2G9XPVJF9W0BFQFFRJ SET name = "Kevin";SLEEP 2s;UPDATE person:01FS8RCP2G9XPVJF9W0BFQFFRJ SET name = "Kevin Jackson";
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

Let's try by creating a new person, then using the `SLEEP` statement to wait for 2 seconds and then updating the person, so we can see the 2-second time difference in the `time.updated_at` field.

You can also use custom functions as default fields, such as the increment example we covered in our lesson on record IDs.

```
DEFINE FIELD serial_id    ON TABLE person    TYPE number    VALUE fn::increment("person");
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

## Field permissions

Field permissions follow the same syntax as table permissions.

As an example, we can allow users to only update the shipping address on the order table if the order hasn't shipped yet.

```
DEFINE FIELD time.shipped_at    ON TABLE order    TYPE option<datetime>    PERMISSIONS      FOR select WHERE in.email = $auth.email,      FOR create NONE,      FOR update WHERE in.email = $auth.email AND time.shipped_at is NONE;
```

![Surrealist Icon](https://surrealdb.com/assets/static/fdfe2c20f5941d5e.D0guSOhZ.webp) Run Query

## Summary

There's a lot that the `DEFINE FIELD` statement can do so let's just summarise here.

The `DEFINE FIELD` statement allows us to define:

- Fields independently from the `DEFINE TABLE` statement
- Data types, such as strings, arrays and objects. Including the flexible type, which allows us to have schemaless fields on schemafull tables.
- Constraints and assertions, such as using a function for email validation.
- Default values, such as using the `time::now()` function to automatically create and update the `time.created_at` and `time.updated_at` fields.
- Field level `PERMISSIONS`, which can be done independently for each CRUD operation or all in one group.

Previous

Define tables, views and changefeeds

[Previous](https://surrealdb.com/learn/fundamentals/schemafull/define-table)

Next lesson

Schemafull CRUD

[Next lesson](https://surrealdb.com/learn/fundamentals/schemafull/schemafull-crud)

```json
{"@context":"https://schema.org","@type":"Course","name":"SurrealDB Fundamentals","description":"The most efficient way to learn SurrealDB through guided hands-on learning","url":"https://surrealdb.com/learn/fundamentals","inLanguage":"en","isAccessibleForFree":false,"provider":{"@type":"Organization","name":"SurrealDB","url":"https://surrealdb.com"},"hasPart":[{"@type":"LearningResource","name":"SurrealDB Fundamentals","url":"https://surrealdb.com/learn/fundamentals"},{"@type":"LearningResource","name":"Introduction","url":"https://surrealdb.com/learn/fundamentals"},{"@type":"LearningResource","name":"Welcome to SurrealDB University","url":"https://surrealdb.com/learn/fundamentals/intro/welcome"},{"@type":"LearningResource","name":"Intro to SurrealDB","url":"https://surrealdb.com/learn/fundamentals/intro/surrealdb"},{"@type":"LearningResource","name":"Why SurrealQL is SQL-like","url":"https://surrealdb.com/learn/fundamentals/intro/surrealql"},{"@type":"LearningResource","name":"Part 1: Schemaless CRUD","url":"https://surrealdb.com/learn/fundamentals/schemaless"},{"@type":"LearningResource","name":"Introduction","url":"https://surrealdb.com/learn/fundamentals/schemaless"},{"@type":"LearningResource","name":"Record IDs","url":"https://surrealdb.com/learn/fundamentals/schemaless/record-ids"},{"@type":"LearningResource","name":"Inserting data","url":"https://surrealdb.com/learn/fundamentals/schemaless/inserting-data"},{"@type":"LearningResource","name":"Reading data","url":"https://surrealdb.com/learn/fundamentals/schemaless/reading-data"},{"@type":"LearningResource","name":"Updating data","url":"https://surrealdb.com/learn/fundamentals/schemaless/updating-data"},{"@type":"LearningResource","name":"Deleting data","url":"https://surrealdb.com/learn/fundamentals/schemaless/deleting-data"},{"@type":"LearningResource","name":"Part 2: Adding relationships","url":"https://surrealdb.com/learn/fundamentals/relationships"},{"@type":"LearningResource","name":"Introduction","url":"https://surrealdb.com/learn/fundamentals/relationships"},{"@type":"LearningResource","name":"Graph relations","url":"https://surrealdb.com/learn/fundamentals/relationships/graph-relations"},{"@type":"LearningResource","name":"Record links","url":"https://surrealdb.com/learn/fundamentals/relationships/record-links"},{"@type":"LearningResource","name":"Relational style joins","url":"https://surrealdb.com/learn/fundamentals/relationships/relational-style"},{"@type":"LearningResource","name":"Part 3: Making it schemafull","url":"https://surrealdb.com/learn/fundamentals/schemafull"},{"@type":"LearningResource","name":"Introduction","url":"https://surrealdb.com/learn/fundamentals/schemafull"},{"@type":"LearningResource","name":"Define tables, views and changefeeds","url":"https://surrealdb.com/learn/fundamentals/schemafull/define-table"},{"@type":"LearningResource","name":"Define fields, constraints and assertions","url":"https://surrealdb.com/learn/fundamentals/schemafull/define-fields"},{"@type":"LearningResource","name":"Schemafull CRUD","url":"https://surrealdb.com/learn/fundamentals/schemafull/schemafull-crud"},{"@type":"LearningResource","name":"Part 4: Making it secure","url":"https://surrealdb.com/learn/fundamentals/security"},{"@type":"LearningResource","name":"Introduction","url":"https://surrealdb.com/learn/fundamentals/security"},{"@type":"LearningResource","name":"Authentication","url":"https://surrealdb.com/learn/fundamentals/security/authentication"},{"@type":"LearningResource","name":"Query capabilities","url":"https://surrealdb.com/learn/fundamentals/security/query-capabilities"},{"@type":"LearningResource","name":"Part 5: Making it performant","url":"https://surrealdb.com/learn/fundamentals/performance"},{"@type":"LearningResource","name":"Introduction","url":"https://surrealdb.com/learn/fundamentals/performance"},{"@type":"LearningResource","name":"Indexing \u0026 data model considerations","url":"https://surrealdb.com/learn/fundamentals/performance/index-data-model"},{"@type":"LearningResource","name":"Deployment \u0026 storage layer considerations","url":"https://surrealdb.com/learn/fundamentals/performance/deployment-storage"},{"@type":"LearningResource","name":"Completion","url":"https://surrealdb.com/learn/fundamentals/completion"}]}
```

```json
{"@context":"https://schema.org","@type":"LearningResource","name":"Define fields, constraints and assertions","description":"Define fields, constraints and assertions","url":"https://surrealdb.com/learn/fundamentals/schemafull/define-fields","learningResourceType":"lesson","isPartOf":{"@type":"Course","name":"SurrealDB Fundamentals","url":"https://surrealdb.com/learn/fundamentals"},"position":21}
```

```json
{"@context":"https://schema.org","@type":"Organization","name":"SurrealDB","url":"https://surrealdb.com","logo":"https://surrealdb.com/assets/static/logo.BG7_TG2b.svg","description":"SurrealDB is the unified data layer for AI. A multi-model database for documents, graphs, vectors, and time-series.","foundingDate":"2022","hasCertification":[{"@type":"Certification","name":"SOC 2 Type 2"},{"@type":"Certification","name":"GDPR"},{"@type":"Certification","name":"Cyber Essentials Plus"},{"@type":"Certification","name":"ISO 27001"}],"owns":[{"@type":"SoftwareApplication","name":"SurrealDB","url":"https://surrealdb.com/surrealdb"},{"@type":"SoftwareApplication","name":"Agent Memory","url":"https://surrealdb.com/agent-memory"}],"knowsAbout":["multi-model databases","document databases","graph databases","vector search","time-series databases","SurrealQL","Agent Memory","real-time databases","embedded databases","context layer","graph ontology","distributed database","knowledge graphs","distributed transaction protocols","highly-scalable databases"],"sameAs":["https://www.wikidata.org/wiki/Q124316308","https://github.com/surrealdb/surrealdb","https://twitter.com/surrealdb","https://www.youtube.com/@surrealdb","https://www.linkedin.com/company/surrealdb","https://discord.gg/surrealdb","https://www.reddit.com/r/surrealdb","https://www.instagram.com/surrealdb","https://medium.com/surrealdb","https://dev.to/surrealdb"]}
```

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://surrealdb.com"},{"@type":"ListItem","position":2,"name":"Learn","item":"https://surrealdb.com/learn"},{"@type":"ListItem","position":3,"name":"Define fields","item":"https://surrealdb.com/learn/fundamentals/schemafull/define-fields"}]}
```
