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

# Source Configuration

> Every Nextedy POWERSHEET sheet begins with a question: *what data should appear?* The `sources` array in a sheet configuration answers that question.

export const LastReviewed = ({date}) => {
  if (!date) return null;
  const formatted = new Date(`${date}T00:00:00Z`).toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric",
    timeZone: "UTC"
  });
  return <p className="mt-10 text-sm text-gray-400 dark:text-zinc-500 not-prose">
      Last reviewed on {formatted}
    </p>;
};

## Sources as the Data Pipeline

Think of sources as the plumbing between your data model and the sheet surface. The data model declares what entity types exist and how they relate. The columns define what users see. Sources sit in between, translating domain relationships into concrete data queries.

<Frame>
  <img src="https://mintcdn.com/none-17b4493f/3Zik2OH750CE3kB4/powersheet/diagrams/concepts/source-configuration/diagram-1.svg?fit=max&auto=format&n=3Zik2OH750CE3kB4&q=85&s=7fce3678a7f4fd8654facc26ea8162f4" alt="diagram" style={{ width: "560px", maxWidth: "100%" }} width="560" height="200" data-path="powersheet/diagrams/concepts/source-configuration/diagram-1.svg" />
</Frame>

A sheet configuration's root structure includes `sources` alongside `columns`, `views`, `renderers`, `formatters`, `styles`, and `sortBy`. While columns control presentation and formatters control appearance rules, sources control *what data enters the sheet in the first place*.

## Anatomy of a Source

Each source is an object in the `sources` array with the following parts:

| Property          | Required | Purpose                                                 |
| ----------------- | -------- | ------------------------------------------------------- |
| `id`              | Yes      | Unique identifier referenced by other settings          |
| `model`           | Yes      | Data model the source binds to (typically `rtm`)        |
| `query`           | Yes      | Defines which entity type to fetch and optional filters |
| `expand`          | No       | Specifies which navigation properties to traverse       |
| `entityFactory`   | No       | Default property values for newly created records       |
| `name` or `title` | No       | Human-readable label for the source                     |

The `id` is a user-defined string that acts as a reference key. It connects the source to the rest of the sheet configuration. Choose descriptive identifiers that reflect the entity type being queried -- for example, `user_needs` rather than `source1`.

The `model` property binds the source to a specific data model -- almost always `rtm`, the Requirements Traceability Model that declares your entity types and relationships. Without `model`, Powersheet has no way to resolve the `from` entity type or the navigation properties used in `expand`. Treat `model` as a required field alongside `id` and `query`.

### The Query Object

The `query` property controls data retrieval:

* **`from`** (required) -- The entity type name from your data model. This tells Powersheet which type of work items to load. For example, `from: UserNeed` fetches all entities of type `UserNeed` as defined in your `domainModelTypes`.

* **`where`** (optional) -- A filter predicate that narrows the result set. The predicate value can be static or dynamic. Dynamic values use the `() =>` notation to evaluate JavaScript expressions at runtime. This is particularly useful for date-based filtering or parameterized queries.

* **`take`** (optional) -- Limits the number of records returned.

* **`orderBy`** (optional) -- Controls server-side ordering of results.

<Tip title="Dynamic Filters with Expressions">
  Source queries support **dynamic value expressions** using `() => expression` syntax. For example, to filter for future dates only: `">": "() => new Date().toISOString()"`. You can also inject widget parameters: `"==": "() => context.parameters.client"`. See [Dynamic Value Expressions](/powersheet/concepts/dynamic-expressions) for the full reference on the context object and expression patterns.
</Tip>

### The Expand Property

The `expand` property is where source configuration connects most directly to the data model. Each entry in the `expand` array specifies a **navigation property name** -- the same name defined in the data model's relationship `direct.name` or `back.name` fields.

Expansion can be nested, letting you traverse multi-level hierarchies:

```yaml theme={null}
sources:
  - id: user_needs
    model: rtm
    query:
      from: UserNeed
    expand:
      - name: systemRequirements
        expand:
          - name: systemRequirement
```

In this example, the source starts from `UserNeed` entities, expands into the `systemRequirements` association, and then further into each `systemRequirement` target entity. Each expansion level corresponds to a new row level in the sheet.

<Warning title="Expansion Depth Affects Performance">
  Every expansion level triggers additional data retrieval. Deeply nested expansions -- three or more levels -- increase load time and memory usage. Design your sources to expand only the levels your sheet actually displays.
</Warning>

## How Cardinality Shapes Sources

The relationship cardinality defined in your data model dictates the expand pattern and, by extension, the column binding syntax and UI behavior. This is one of the most important concepts to internalize.

<Frame>
  <img src="https://mintcdn.com/none-17b4493f/3Zik2OH750CE3kB4/powersheet/diagrams/concepts/source-configuration/diagram-2.svg?fit=max&auto=format&n=3Zik2OH750CE3kB4&q=85&s=13b3486af6f18dbbce53ed7ed70385bf" alt="diagram" style={{ width: "560px", maxWidth: "100%" }} width="560" height="320" data-path="powersheet/diagrams/concepts/source-configuration/diagram-2.svg" />
</Frame>

### Many-to-One (N:1)

When a relationship is `many-to-one` -- for example, many `UserNeed` entities belong to one `Chapter` -- the source uses the **direct** navigation property name (singular form). The expand entry is a single level:

```yaml theme={null}
expand:
  - name: chapter
```

In the columns section, this produces a **scalar navigation property**: `chapter` renders as a single-value reference picker, and `chapter.title` lets you display a read-only property of the referenced entity. The key insight is that N:1 relationships do not create new row levels -- they add reference columns to the existing level.

### One-to-Many (1:N)

The reverse relationship -- one `Chapter` has many `UserNeed` children -- uses the **back** navigation property name (plural form):

```yaml theme={null}
expand:
  - name: userNeeds
```

This creates a **new row level** in the sheet. When the user expands a `Chapter` row, the child `UserNeed` rows appear beneath it. The column binding for the child level uses the navigation property name directly (e.g., `userNeeds`) without dot notation.

### Many-to-Many (M:N)

Many-to-many relationships are the most complex case. They involve an **association entity** that sits between the two related types. The source expand requires two levels -- one for the association, one for the target entity:

```yaml theme={null}
expand:
  - name: systemRequirements
    expand:
      - name: systemRequirement
```

The column binding mirrors this two-level structure: `systemRequirements.systemRequirement`. The association layer (`systemRequirements`, plural) is the collection of links, while the target layer (`systemRequirement`, singular) is the actual entity. In the UI, this pattern produces a multi-item reference picker.

<Note title="Naming Convention Matters">
  The navigation property names in your source `expand` must exactly match the `direct.name` or `back.name` values in your data model relationships. A mismatch between the model and the source configuration is one of the most common causes of empty sheets. See [Entity Types and Relationships](/powersheet/concepts/entity-types-and-relationships) and [Link Cardinality](/powersheet/concepts/link-cardinality) for details on how relationships define these names.
</Note>

## Entity Factory: Defaults for New Records

The `entityFactory` property defines default values that Powersheet assigns when a user creates a new record from within the sheet. This is useful for enforcing consistent initial states:

```yaml theme={null}
sources:
  - id: user_needs
    model: rtm
    query:
      from: UserNeed
    entityFactory:
      Status: "Draft"
      Priority: "Medium"
```

When a user adds a new `UserNeed` row, the `Status` field automatically populates with "Draft" and `Priority` with "Medium". Without `entityFactory`, new records would have empty fields (or whatever defaults the underlying platform provides).

Entity factories also support dynamic value expressions:

```yaml theme={null}
entityFactory:
  Client: "() => context.parameters.client"
```

This makes the factory value depend on the widget parameters passed to the sheet at load time, enabling context-sensitive defaults. Entity factories can be defined at any expansion level, not just the root source. Each `expand` entry can carry its own `entityFactory` for the child level.

## Multiple Sources

A sheet configuration can define multiple sources in the `sources` array. Each source gets its own `id`, `model`, query, and expansion tree. This allows a single sheet to display data from different root entity types side by side or in separate sections.

```yaml theme={null}
sources:
  - id: user_needs
    model: rtm
    query:
      from: UserNeed
    expand:
      - name: systemRequirements
        expand:
          - name: systemRequirement

  - id: hazards
    model: rtm
    query:
      from: Hazard
    expand:
      - name: riskControls
        expand:
          - name: riskControl
```

Each source operates independently -- it runs its own query and builds its own expansion tree. The columns section then references bindings from any of the configured sources.

## The Three-Layer Connection

The relationship between data model, sources, and columns follows a strict chain:

1. **Data model** declares entity types (e.g., `UserNeed`, `SystemRequirement`) and relationships with navigation property names (e.g., `direct.name: chapter`, `back.name: systemRequirements`).

2. **Sources** reference those navigation property names in `expand` entries and the entity type names in `query.from`, binding to the data model via the `model` property. The source does not redefine the relationships -- it activates specific paths from the data model.

3. **Columns** use dot-separated binding paths built from the same navigation property names. The binding path `systemRequirements.systemRequirement.title` means: traverse the `systemRequirements` association, reach the `systemRequirement` entity, and display its `title` property.

If the data model changes a navigation property name, both the source and the column bindings must update to match. This tight coupling is intentional -- it ensures that the sheet always reflects the actual data structure.

<Info title="Verify in application">
  The interplay between model, source, and column configuration is best verified by loading the sheet in the Powersheet widget and confirming that expansions and column data appear as expected.
</Info>

## Common Misconceptions

**"Sources define the schema."** Sources do not define entity types or properties -- the data model does. Sources only specify which parts of the model to query and expand. If you need to add a new entity type, modify the data model first, then add a source entry.

**"More expand levels means richer data."** Each expand level adds a data-loading step. Expanding four or five levels deep may produce impressive hierarchy trees but comes at a performance cost. Most practical sheets use one to three expansion levels.

**"The `id` must match the entity type name."** The source `id` is a free-form string. While it is good practice to use a descriptive name that hints at the entity type (e.g., `user_needs` for `UserNeed`), there is no technical requirement for the `id` to match the `from` value.

**"Dynamic where clauses run on the server."** The `() =>` expressions in `where` predicates are evaluated on the client side before the query is sent. This means the expression has access to the browser context (including widget parameters) but cannot reference server-side variables directly.

## Putting It All Together

Consider a requirements traceability sheet that displays `UserNeed` entities at the root, their linked `SystemRequirement` entities as children, and further nested `DesignRequirement` entities at the third level:

```yaml theme={null}
sources:
  - id: user_needs
    model: rtm
    query:
      from: UserNeed
    entityFactory:
      Status: "Draft"
    expand:
      - name: systemRequirements
        expand:
          - name: systemRequirement
            expand:
              - name: designRequirements
                expand:
                  - name: designRequirement

columns:
  title:
    title: User Need
    hasFocus: true
  systemRequirements.systemRequirement:
    title: System Requirement
    list:
      search:
        - objectId
        - title
      createNew: true
  systemRequirements.systemRequirement.title:
    title: SysReq Title
    hasFocus: true
  systemRequirements.systemRequirement.designRequirements.designRequirement:
    title: Design Requirement
  systemRequirements.systemRequirement.designRequirements.designRequirement.title:
    title: DesReq Title
    hasFocus: true
```

In this configuration, each column binding mirrors the source expansion path. The `systemRequirements` and `designRequirements` segments are association-level navigation properties (M:N), while `systemRequirement` and `designRequirement` are the target entity-level properties. This pattern -- expanding through the association layer then into the entity -- is the standard approach for M:N relationships in Powersheet.

## Related Topics

For practical steps on configuring sources in your own sheets, see the [Sheet Configuration Guides](/powersheet/guides/sheet-configuration/index). To understand the data model relationships that sources reference, see [Entity Types and Relationships](/powersheet/concepts/entity-types-and-relationships) and [Link Cardinality](/powersheet/concepts/link-cardinality). For a side-by-side comparison of the model and sheet configuration layers, see [Data Model vs Sheet Configuration](/powersheet/concepts/data-model-vs-sheet-config). For details on the `() =>` expression syntax used in `where` clauses and entity factories, see [Dynamic Value Expressions](/powersheet/concepts/dynamic-expressions).

<LastReviewed date="2026-06-08" />
