> For the complete documentation index, see [llms.txt](https://docs.ondeva.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ondeva.com/data/custom-tables/best-practices.md).

# Best Practices

### **Design for Queryability**

Structure your tables to make querying easy and predictable:

* Use **identifying columns** for anything users will pick in dropdowns or reference selectors.
* Prefer **flat fields** for filterable or sortable data (e.g. status, type, created\_at).
* If you’ll be using filters in UI components or automation, keep field names short and consistent (`status`, `owner`, `is_published`).

{% hint style="info" %}
Use **Dropdown** or **Multiple Choice** fields for controlled vocabularies like categories, states, or tags.
{% endhint %}

***

### **Normalize for Relationships — But Don’t Overdo It**

Ondeva supports **table references** (like foreign keys), allowing you to link entries across tables. Use them when:

* Data is **reused** in multiple places (e.g. users, clients, roles)
* You need to enforce **consistency** across submissions or components

**But avoid excessive normalization** for operational or analytical data. For example:

* If you're tracking tasks, log entries, or user actions — and frequently need to **group, sort, or filter** by related values — it’s often better to keep those fields **in the same table**.

{% hint style="info" %}
Good rule of thumb:\
**Normalize for reusability and UI clarity.**\
**Denormalize for filtering, grouping, and performance.**
{% endhint %}

#### When to Use Table References

* “One-to-one” or “many-to-one” relationships where a dropdown picker makes UX cleaner
* Data that’s maintained separately (e.g. Teams, Plans, Categories)

#### When to Flatten into the Same Table

* Metrics, submissions, or logs you’ll run analytics on
* Dynamic data where query speed matters more than data purity

{% hint style="warning" %}
Avoid deep reference chains — they create overhead and slow down performance in large apps.
{% endhint %}

***

### **Use ‘One Entry Per User’ for Personal Data**

For profile-like data (user preferences, application forms, onboarding data), enable the **One Entry Per User** setting:

* Prevents duplicate submissions
* Simplifies queries and access control
* Automatically ties data to the logged-in user

{% hint style="info" %}
Ideal for forms like “My Account”, “Startup Registration”, “Grant Application”, etc.
{% endhint %}

***

### **Model State Transitions Explicitly**

Use fields like `status`, `phase`, or `is_active` to represent the state of your entries. These fields allow:

* Workflows to branch based on state
* UI to show dynamic labels or badges
* Queries to filter logically (e.g. “only active”, “only pending approval”)

{% hint style="info" %}
Combine with [**Workflow steps**](/workflow/steps-reference.md) that update these fields in automation flows.
{% endhint %}

***

### **Use Default Values to Streamline Entry Creation**

For operational tables (e.g. task tracking, logs, form submissions), set defaults to:

* Reduce user input friction
* Ensure consistency across manual and automated inserts
* Prevent missing or inconsistent data downstream

Example: Set default `status = pending`, `priority = normal`, or `country = DE`.

***

### **Validate Where It Matters**

Field-level validation prevents fragile downstream logic. Use:

* **Required** fields to avoid nulls
* **Regex** to ensure structure (e.g. emails, phone numbers)
* **Unique per user** for IDs, usernames, emails
* **Formula validations** for business rules (e.g. start\_date < end\_date)

{% hint style="info" %}
Don’t over-validate early. Start with must-haves, then layer in business logic over time.
{% endhint %}

***

### **Avoid Complex JSON in Text Fields**

Ondeva supports complex logic — but don’t overuse `Text` fields to store structured blobs. Instead:

* Use **rich text** for formatted content
* Use **JSON-compatible** structures only when paired with processing logic in workflows

{% hint style="info" %}
If you need to store complex objects, consider breaking them into related tables or use [`Create Object`](/workflow/steps-reference/parameters-and-variables.md#create-object) + [`Save Entry`](/workflow/steps-reference/data.md#save-entry) via workflows.
{% endhint %}

***

### **Tag and Track Metadata When Needed**

For audit trails or analytics, add fields like:

* `created_at` (date)
* `created_by` (user reference)
* `last_updated` (date)
* `is_deleted` (soft delete flag)

These can power:

* Admin interfaces
* Time-based automations
* Conditional access to data

***

### Summary

Strong data modeling leads to strong apps. When building with Ondeva:

* Keep schemas clean, normalized, and queryable
* Use built-in settings to simplify access control and validation
* Combine structured tables with workflows to build powerful, self-sustaining systems

**Tables aren’t just storage — they’re the living logic of your app.**


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ondeva.com/data/custom-tables/best-practices.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
