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

# Creating Entities

> Base44 entities are defined locally in your project and then pushed to the Base44 backend.

<Warning>
  This page is part of an AI coding agent skill and is written for agents, not humans. For the human-readable Base44 docs, see the [developer documentation](/developers).
</Warning>

# Creating Entities

Base44 entities are defined locally in your project and then pushed to the Base44 backend.

## Critical: File Naming

Entity files MUST use kebab-case naming: `{kebab-case-name}.jsonc`

| Entity Name   | File Name            |
| ------------- | -------------------- |
| `Task`        | `task.jsonc`         |
| `TeamMember`  | `team-member.jsonc`  |
| `ActivityLog` | `activity-log.jsonc` |

WRONG: `TeamMember.jsonc`, `teamMember.jsonc`
RIGHT: `team-member.jsonc`

## Table of Contents

* [Creating Entities](#creating-entities)
  * [Entity Directory](#entity-directory)
  * [How to Create an Entity](#how-to-create-an-entity)
  * [Entity Schema Structure](#entity-schema-structure)
  * [Supported Field Types](#supported-field-types)
  * [Field Properties](#field-properties)
  * [Complete Example](#complete-example)
  * [Naming Conventions](#naming-conventions)
  * [Relationships Between Entities](#relationships-between-entities)
  * [Row Level Security (RLS)](#row-level-security-rls)
  * [Field Level Security (FLS)](#field-level-security-fls)
  * [Pushing Entities](#pushing-entities)

## Entity Directory

All entity definitions must be placed in the `base44/entities/` folder in your project root. Each entity is defined in its own `.jsonc` file.

Example structure:

```
my-app/
  base44/
    entities/
      user.jsonc
      product.jsonc
      order.jsonc
```

## How to Create an Entity

1. Create a new `.jsonc` file in the `base44/entities/` directory
2. Define your entity schema following the structure below
3. Push the changes to Base44 using the CLI

## Entity Schema Structure

Each entity file follows a JSON Schema-like structure:

```jsonc theme={null}
{
  "name": "EntityName",       // PascalCase entity name
  "type": "object",           // Always "object"
  "properties": {
    // Define your fields here
  },
  "required": ["field1"]      // Array of required field names
}
```

### Common Mistake: Nested Schema Property

**WRONG** - Do NOT wrap properties in a `schema` object:

```jsonc theme={null}
{
  "name": "Task",
  "description": "A task entity",
  "schema": {                    // ❌ WRONG - don't use nested "schema"
    "type": "object",
    "properties": { ... }
  }
}
```

**CORRECT** - Put `type` and `properties` at the top level:

```jsonc theme={null}
{
  "name": "Task",
  "description": "A task entity",
  "type": "object",              // ✅ CORRECT - top level
  "properties": { ... }          // ✅ CORRECT - top level
}
```

This is a common mistake that will cause "Invalid schema: Schema must have a 'type' field" errors when pushing entities.

## Supported Field Types

### String

Basic text field:

```jsonc theme={null}
{
  "title": {
    "type": "string",
    "description": "Task title"
  }
}
```

With format:

```jsonc theme={null}
{
  "due_date": {
    "type": "string",
    "format": "date",
    "description": "Due date"
  }
}
```

Available formats: `date`, `date-time`, `time`, `email`, `uri`, `hostname`, `ipv4`, `ipv6`, `uuid`, `file`, `regex`, `richtext`

### String with Enum

Constrained to specific values:

```jsonc theme={null}
{
  "status": {
    "type": "string",
    "enum": ["todo", "in_progress", "done"],
    "default": "todo",
    "description": "Current status"
  }
}
```

### Number

```jsonc theme={null}
{
  "position": {
    "type": "number",
    "description": "Position for ordering"
  }
}
```

### Integer

For whole numbers only:

```jsonc theme={null}
{
  "quantity": {
    "type": "integer",
    "description": "Item quantity",
    "minimum": 0,
    "maximum": 1000
  }
}
```

### Binary

For file/blob data:

```jsonc theme={null}
{
  "attachment": {
    "type": "binary",
    "description": "File attachment"
  }
}
```

### Boolean

```jsonc theme={null}
{
  "notify_on_change": {
    "type": "boolean",
    "default": true,
    "description": "Enable notifications"
  }
}
```

### Array of Strings

```jsonc theme={null}
{
  "labels": {
    "type": "array",
    "items": { "type": "string" },
    "description": "Task labels/tags"
  }
}
```

### Array of Objects

```jsonc theme={null}
{
  "attachments": {
    "type": "array",
    "description": "File attachments",
    "items": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "url": { "type": "string" },
        "type": { "type": "string" }
      }
    }
  }
}
```

## Field Properties

| Property      | Description                                                                                                               |
| ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `type`        | Data type: `string`, `number`, `integer`, `boolean`, `array`, `object`, `binary`                                          |
| `description` | Human-readable description of the field                                                                                   |
| `enum`        | Array of allowed values (for strings)                                                                                     |
| `enumNames`   | Human-readable labels for enum values (same order as `enum`)                                                              |
| `default`     | Default value when not provided                                                                                           |
| `format`      | Format hint: `date`, `date-time`, `time`, `email`, `uri`, `hostname`, `ipv4`, `ipv6`, `uuid`, `file`, `regex`, `richtext` |
| `items`       | Schema for array items                                                                                                    |
| `properties`  | Nested properties for object types                                                                                        |
| `$ref`        | Reference to another schema definition                                                                                    |
| `minLength`   | Minimum string length                                                                                                     |
| `maxLength`   | Maximum string length                                                                                                     |
| `pattern`     | Regex pattern for string validation                                                                                       |
| `minimum`     | Minimum value for numbers                                                                                                 |
| `maximum`     | Maximum value for numbers                                                                                                 |
| `rls`         | Field-level security rules (see Field Level Security section)                                                             |

## Complete Example

Here's a complete entity definition for a Task:

```jsonc theme={null}
{
  "name": "Task",
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "description": "Task title"
    },
    "description": {
      "type": "string",
      "description": "Task description"
    },
    "status": {
      "type": "string",
      "enum": ["todo", "in_progress", "done"],
      "default": "todo",
      "description": "Current status of the task"
    },
    "board_id": {
      "type": "string",
      "description": "Board this task belongs to"
    },
    "assignee_email": {
      "type": "string",
      "description": "Email of assigned user"
    },
    "priority": {
      "type": "string",
      "enum": ["low", "medium", "high"],
      "default": "medium",
      "description": "Task priority"
    },
    "due_date": {
      "type": "string",
      "format": "date",
      "description": "Due date"
    },
    "labels": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Task labels/tags"
    }
  },
  "required": ["title"]
}
```

## Naming Conventions

* **Entity name**: Use PascalCase with alphanumeric characters only (e.g., `Task`, `TeamMember`, `ActivityLog`)
  * Must match pattern: `/^[a-zA-Z0-9]+$/`
  * Valid: `Task`, `TeamMember`, `Order123`
  * Invalid: `Team_Member`, `Team-Member`, `Team Member`
* **File name**: Use kebab-case matching the entity (e.g., `task.jsonc`, `team-member.jsonc`, `activity-log.jsonc`)
* **Field names**: Use snake\_case (e.g., `board_id`, `user_email`, `due_date`)

## Relationships Between Entities

To create relationships between entities, use ID reference fields:

```jsonc theme={null}
{
  "board_id": {
    "type": "string",
    "description": "Board this task belongs to"
  },
  "team_id": {
    "type": "string",
    "description": "Associated team ID"
  }
}
```

## Row Level Security (RLS)

Row Level Security (RLS) controls which records users can access based on their identity and attributes. RLS rules are defined per entity inside the `rls` field of the schema.

**Important:** If no RLS is defined, all records are accessible to all users.

### RLS Operations

RLS supports five operations:

| Operation | Description                                             |
| --------- | ------------------------------------------------------- |
| `create`  | Control who can add new records                         |
| `read`    | Control who can view records                            |
| `update`  | Control who can modify records                          |
| `delete`  | Control who can remove records                          |
| `write`   | Shorthand for `create`, `update`, and `delete` combined |

### Permission Values

Each operation accepts one of the following values:

1. **`true`** - Allow all users (including anonymous/unauthenticated)
2. **`false`** - Block all users
3. **Condition object** - Allow users matching the condition

### Template Variables

Use template variables to reference the current user's attributes:

| Template                   | Description                                |
| -------------------------- | ------------------------------------------ |
| `{{user.id}}`              | The user's ID                              |
| `{{user.email}}`           | The user's email                           |
| `{{user.role}}`            | The user's role                            |
| `{{user.data.field_name}}` | Custom field from the user's `data` object |

### Built-in Entity Attributes

Every entity record has these built-in attributes available for RLS rules:

| Attribute      | Description                              |
| -------------- | ---------------------------------------- |
| `id`           | Unique record identifier                 |
| `created_date` | Timestamp when record was created        |
| `updated_date` | Timestamp when record was last updated   |
| `created_by`   | Email of the user who created the record |

### Rule Types

There are two condition types you can use:

**1. Entity-to-user comparison** - Compare record fields to the current user's values:

```jsonc theme={null}
{
  "created_by": "{{user.email}}"
}
```

**2. User condition check** - Check user properties directly using `user_condition`:

```jsonc theme={null}
{
  "user_condition": { "role": "admin" }
}
```

**Important notes:**

* `user_condition` only supports **simple equality** (e.g., `{ "role": "admin" }`)
* **Entity field filtering requires `data.` prefix:** Use `{ "data.fieldname": value }` to filter by entity field values
* For `data.*` field comparisons, you can use operators: `$in`, `$nin`, `$ne`, `$all`
* Logical operators `$or`, `$and`, `$nor` are available for combining conditions

⚠️ **For advanced RLS patterns and examples, see [rls-examples.md](https://docs.base44.com/developers/skills/base44-cli/references/rls-examples.md)**

### RLS Examples

**Owner-only access:**

```jsonc theme={null}
{
  "created_by": "{{user.email}}"
}
```

**Department-based access:**

```jsonc theme={null}
{
  "data.department": "{{user.data.department}}"
}
```

**Admin-only access:**

```jsonc theme={null}
{
  "user_condition": { "role": "admin" }
}
```

**Complete RLS configuration:**

```jsonc theme={null}
{
  "name": "Task",
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "description": "Task title"
    },
    "status": {
      "type": "string",
      "enum": ["todo", "in_progress", "done"],
      "default": "todo"
    }
  },
  "required": ["title"],
  "rls": {
    "create": true,
    "read": { "created_by": "{{user.email}}" },
    "update": { "created_by": "{{user.email}}" },
    "delete": { "created_by": "{{user.email}}" }
  }
}
```

### Common RLS Patterns

**Public create, admin-only management (e.g., contact forms, waitlists):**

```jsonc theme={null}
{
  "rls": {
    "create": true,
    "read": { "user_condition": { "role": "admin" } },
    "update": { "user_condition": { "role": "admin" } },
    "delete": { "user_condition": { "role": "admin" } }
  }
}
```

**Owner-only access:**

```jsonc theme={null}
{
  "rls": {
    "create": true,
    "read": { "created_by": "{{user.email}}" },
    "update": { "created_by": "{{user.email}}" },
    "delete": { "created_by": "{{user.email}}" }
  }
}
```

**Logged-in users only:**

```jsonc theme={null}
{
  "rls": {
    "create": { "user_condition": { "id": "{{user.id}}" } },
    "read": true,
    "update": { "created_by": "{{user.email}}" },
    "delete": { "created_by": "{{user.email}}" }
  }
}
```

### Limitations

* **user\_condition is equality only:** `user_condition` only supports exact match (e.g., `{ "role": "admin" }`) - no operators
* **No comparison operators on user\_condition:** `$gt`, `$lt`, `$regex`, `$expr`, `$where` are NOT supported for user conditions
* **No deeply nested templates:** Templates like `{{user.data.profile.department}}` may not work

**Supported operators:**

* **Logical operators:** `$or`, `$and`, `$nor` for combining multiple conditions
* **Field operators (for `data.*` fields only):** `$in`, `$nin`, `$ne`, `$all`
* **Entity field filtering:** Use `data.` prefix to filter by entity field values (e.g., `{ "data.status": "published" }` or `{ "data.completed": true }`)

⚠️ **See [rls-examples.md](https://docs.base44.com/developers/skills/base44-cli/references/rls-examples.md) for comprehensive RLS patterns and examples**

### Complex Access Patterns

For complex access patterns that require multiple conditions (e.g., "owner OR admin"), you have two options:

1. **Use the Base44 Dashboard UI** - The dashboard allows adding multiple rules per operation with OR logic
2. **Use separate entities** - Split data into multiple entities with different access rules
3. **Use backend functions** - Implement custom access logic in backend functions

## Field Level Security (FLS)

Field Level Security allows you to control access to individual fields within an entity. FLS rules are defined within each field's schema using the `rls` property.

### FLS Operations

FLS supports the same operations as entity-level RLS:

| Operation | Description                                             |
| --------- | ------------------------------------------------------- |
| `create`  | Control who can set this field when creating records    |
| `read`    | Control who can view this field                         |
| `update`  | Control who can modify this field                       |
| `delete`  | Control who can clear this field                        |
| `write`   | Shorthand for `create`, `update`, and `delete` combined |

### FLS Example

```jsonc theme={null}
{
  "name": "Employee",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Employee name"
    },
    "salary": {
      "type": "number",
      "description": "Employee salary",
      "rls": {
        "read": { "user_condition": { "role": "hr" } },
        "update": { "user_condition": { "role": "hr" } }
      }
    },
    "department": {
      "type": "string",
      "description": "Department name"
    }
  },
  "required": ["name"]
}
```

In this example, only users with the `hr` role can read or update the `salary` field. All users with access to the entity can read/update other fields.

### FLS Notes

* If no field-level RLS is defined, the field inherits the entity-level RLS rules
* FLS rules follow the same condition format as entity-level RLS
* Use FLS for sensitive fields like salary, SSN, or internal notes

## Pushing Entities

The `entities push` command will push all entities that exist in the `base44/entities` folder.

```bash theme={null}
npx base44 entities push
```

For more details on the push command, see [entities-push.md](https://docs.base44.com/developers/skills/base44-cli/references/entities-push.md).
