> ## 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.

# Create a Computed Property

> Define a property in your Nextedy POWERSHEET data model or sheet configuration that computes its value dynamically at runtime, using either server-side Velocity templates or client-side JavaScript expressions.

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>;
};

## Prerequisites

* A working data model with at least one entity type
* A sheet configuration displaying entity properties
* Access to the project SVN repository to edit YAML configuration files

## Choose Your Approach

Powersheet supports two mechanisms for computed properties, each suited to different use cases:

| Approach                     | Syntax                                                   | Runs On             | Defined In               | Best For                                                               |
| ---------------------------- | -------------------------------------------------------- | ------------------- | ------------------------ | ---------------------------------------------------------------------- |
| **Server-rendered property** | `serverRender: "$item.id"`                               | Server (Velocity)   | Data-model YAML          | Accessing Polarion services, secure calculations, cross-entity queries |
| **Dynamic value expression** | `formula: "() => context.item.qty * context.item.price"` | Client (JavaScript) | Sheet-configuration YAML | UI-driven calculations, formatting, parameter-based filtering          |

<Tip title="Rule of thumb">
  The two mechanisms live in different files. `serverRender` must be defined in the **data model** YAML (it needs Polarion platform access); `formula` / `() =>` expressions must be defined in the **sheet configuration** YAML (they run client-side and need UI reactivity). Putting either in the wrong file has no effect.
</Tip>

<Frame>
  <img src="https://mintcdn.com/none-17b4493f/-WiVljKlDztH36bB/powersheet/diagrams/guides/server-rendering/create-computed-property/diagram-1.svg?fit=max&auto=format&n=-WiVljKlDztH36bB&q=85&s=6f35ccc2c6a1a2bfe9ac1fbbe6a3b0f2" alt="diagram" style={{ width: "520px", maxWidth: "100%" }} width="520" height="180" data-path="powersheet/diagrams/guides/server-rendering/create-computed-property/diagram-1.svg" />
</Frame>

***

## Option A: Server-Rendered Property (Velocity)

Use this approach when you need to compute a value on the server using Polarion platform services and work item data.

### Step 1: Add the Property to Your Data Model

Open your data model YAML file and add a property with a `serverRender` pattern to the target entity type. The value is a Velocity template expression that the server evaluates for each work item:

```yaml theme={null}
domainModelTypes:
  SystemRequirement:
    polarionType: systemRequirement
    properties:
      title:
        type: string
      computedLabel:
        serverRender: "$item.id - $item.title"
```

The `serverRender` value is a standard Velocity template string. The server evaluates it in a context that includes the current work item and Polarion platform services.

### Step 2: Use Context Variables in Your Template

Server-rendered properties have access to these context variables during evaluation:

| Variable   | Type              | Description                                                                            | Availability             |
| ---------- | ----------------- | -------------------------------------------------------------------------------------- | ------------------------ |
| `$item`    | ModelObject       | Work item model object (`.id`, `.title`, `.status`, `.author`, `.created`, `.updated`) | All work items           |
| `$wi`      | IWorkItem         | Low-level Polarion work item API for operations not available on `$item`               | Work item entities only  |
| `$module`  | IModule           | Current LiveDoc (`.moduleFolder`, `.moduleName`, `.space`)                             | Document-scoped entities |
| `$context` | PowersheetContext | Powersheet context (project, document scope, query helpers)                            | Always                   |
| `$tx`      | Transaction       | Current transaction for read-only operations                                           | Always                   |

In addition, the Polarion platform services (`$trackerService`, `$txService`, `$repositoryService`, `$securityService`) are automatically injected and cached for performance. For the full list and what each service is for, see [Platform Services in the Velocity Templates reference](/powersheet/reference/server-rendering/velocity-templates#platform-services).

**Example** -- concatenate ID and title with a status badge:

```yaml theme={null}
properties:
  statusLabel:
    serverRender: "$item.id [$item.status.id] $item.title"
```

**Example** -- conditional label using Velocity directives:

```yaml theme={null}
properties:
  riskLabel:
    serverRender: "#if($item.riskScore > 5)High Risk#{else}Low Risk#end"
    readable: true
    updatable: false
```

<Tip title="Use Velocity directives for logic">
  Velocity templates support `#if`, `#else`, `#foreach`, `#set`, and other directives. Use them to create dynamic labels, computed statuses, or aggregated displays.
</Tip>

**Example** -- count directly linked work items using `$wi` (the low-level work item API, for methods not available on `$item`):

```yaml theme={null}
properties:
  linkedCount:
    serverRender: "#set($links = $wi.getLinkedWorkItemsStructsDirect())$links.size()"
```

### Step 3: Mark the Property as Read-Only

Server-rendered properties are automatically treated as non-editable by the rendering mechanism. You should explicitly set `readable: true` and `updatable: false` in your property definition to make the intent clear:

```yaml theme={null}
domainModelTypes:
  SystemRequirement:
    polarionType: systemRequirement
    properties:
      computedLabel:
        serverRender: "$item.id - $item.title"
        readable: true
        updatable: false
```

<Warning title="Server-rendered properties are always read-only">
  A property with `serverRender` is always read-only -- even if you set `updatable: true`, the rendering mechanism overrides it and prevents client-side edits, since the value is always recomputed from the template. Setting `updatable: false` explicitly just avoids confusing the column display. See [Configure Read-Only Column](/powersheet/guides/sheet-configuration/configure-read-only-column#how-read-only-resolution-works) for how this interacts with the other read-only resolution rules.
</Warning>

### Step 4: Display the Property in Your Sheet

Add a column in your sheet configuration that binds to the computed property:

```yaml theme={null}
columns:
  computedLabel:
    title: "Requirement Label"
    width: 250
```

The column displays the server-computed value. Since the property is server-rendered, the value is recalculated on each data load and reflects the latest work item state.

### Step 5: Use Custom Field Data in Templates

`customFieldName` maps a data-model property to a Polarion **custom field** by its field ID, so the property reads and writes that custom field's value. Once mapped, you can reference the property within a Velocity template:

```yaml theme={null}
domainModelTypes:
  SystemRequirement:
    polarionType: systemRequirement
    properties:
      riskScore:
        customFieldName: risk_score
      riskSummary:
        serverRender: "#if($item.riskScore > 5)HIGH: Score $item.riskScore#{else}OK#end"
        readable: true
        updatable: false
```

### Step 6: Alias Field Names with serverName

`serverName` aliases a property to a different underlying Polarion field ID: the property keeps its client-facing name in the sheet while reading and writing the field named by `serverName` on the server. Use it when the Polarion field name differs from the name you want to expose:

```yaml theme={null}
properties:
  friendlyName:
    serverName: internalPolarionFieldId
    type: string
```

This lets you expose a user-friendly name in the sheet while mapping to the actual Polarion field behind the scenes.

***

## Option B: Dynamic Value Expression (JavaScript)

Use this approach for client-side calculations in your sheet configuration. Dynamic value expressions use JavaScript arrow function syntax and are evaluated in the browser.

### Step 1: Add a Formula Column

To compute a value from other properties on the current item, use the `formula` property in your column definition:

```yaml theme={null}
columns:
  totalPrice:
    title: "Total Price"
    formula: "() => context.item.quantity * context.item.unitPrice"
```

<Accordion title="Formula writes back to the data source">
  The `formula` property calculates a value and **saves it back** to the underlying field. If you only need to change how a value is displayed without modifying data, use `render` instead.
</Accordion>

### Step 2: Understand Context Availability

Not all context properties are available in every location. The available properties depend on where the expression is used. In the table below, **✅** means the property is available at that location and **`--`** means it is not available:

| Usage Location         | `.user` | `.sources` | `.document` | `.item` | `.value` | `.source` | `.entity` |
| ---------------------- | ------- | ---------- | ----------- | ------- | -------- | --------- | --------- |
| `where`                | ✅       | ✅          | ✅           | --      | --       | --        | --        |
| `entityFactory`        | ✅       | ✅          | --          | --      | --       | --        | --        |
| `formula`              | ✅       | ✅          | --          | ✅       | ✅        | ✅         | ✅         |
| `render` / `renderers` | --      | --         | --          | ✅       | ✅        | --        | --        |
| `formatter`            | --      | --         | ✅           | ✅       | ✅        | --        | --        |
| `display`              | --      | --         | --          | ✅       | ✅        | ✅         | --        |

### Step 3: Use Dynamic Expressions in Different Locations

**Filter a query by current document:**

```yaml theme={null}
sources:
  - id: opportunities
    query:
      from: Opportunity
      where:
        Module:
          "==": "() => context.document.moduleName"
```

**Render custom HTML in a cell:**

```yaml theme={null}
renderers:
  linkedItems: "() => context.value.map((item) => `<b>${item.name}</b>`).join(', ')"
```

**Display a property from a linked entity:**

```yaml theme={null}
columns:
  systemRequirement.document:
    display: "() => context.document.title"
```

**Set initial values for new items from a URL parameter:**

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

<Tip title="Dates require ISO format">
  When using dates in dynamic expressions, always convert to ISO string format: `"() => new Date().toISOString()"`. The resulting value must match the expected data type format.
</Tip>

### Step 4: Add Conditional Formatting

Formatter expressions use a simplified syntax without the `() =>` prefix. The expression is evaluated as a boolean condition directly:

```yaml theme={null}
formatters:
  criticalHighlight:
    expression: "context.item.Probability <= 99"
    style: warningStyle
```

<Note title="Formatter syntax difference">
  Unlike other dynamic expressions, formatter `expression` values do **not** use the `() =>` prefix. They are evaluated as direct boolean conditions.
</Note>

***

## Debugging Computed Properties

### Server-Rendered Properties

If a server-rendered property returns `#SERVER_RENDER_ERROR`, the Velocity template failed to evaluate. Common causes:

| Error Type                  | Cause                            | Fix                                                                       |
| --------------------------- | -------------------------------- | ------------------------------------------------------------------------- |
| `ParseErrorException`       | Invalid Velocity syntax          | Check template for unclosed directives or typos                           |
| `MethodInvocationException` | Called method threw an exception | Verify the method exists on the target object                             |
| `ResourceNotFoundException` | Referenced resource not found    | Check that `$item`, `$module`, or `$wi` is available for your entity type |

<Tip title="Check server logs for details">
  The `#SERVER_RENDER_ERROR` marker in the cell means the template failed. Check the Polarion server logs for the full stack trace, which includes the specific exception type and the failing template expression.
</Tip>

#### Column renders the literal template text, or does not appear at all

A computed column that shows the raw template (e.g. `$item.id - $item.title`) verbatim instead of the evaluated value -- or that does not appear in the sheet at all -- usually points to one of the following. Work through them in order:

1. **Install-time cache not cleared.** This is the most common cause. The `serverRender` annotation is only picked up after the install-time caches are cleared and the server is restarted. Confirm that **both** `[POLARION_DATA]/workspace/.config` **and** `[POLARION_DATA]/workspace/.metadata` were deleted and Polarion was fully restarted -- a stale `.metadata` cache in particular lets the plugin load while server-side rendering silently fails to engage. See [Installing Powersheet, Step 1](/powersheet/getting-started/installation) for the exact procedure.
2. **`polarionType` mismatch.** Confirm the entity's `polarionType` matches the real Polarion work-item type ID **exactly** -- the match is case-sensitive. If it does not match a real type, the property is never bound to live work items and nothing is rendered.
3. **Document caches its column layout.** An existing Powersheet document caches the columns it was opened with, so a newly added column may not appear until you fully close and re-open (or reload) the document -- the in-sheet refresh action alone is not always enough.

<Note title="Diagnostics, not a guarantee">
  These are diagnostic steps for the most frequent causes. If a column still renders its literal template after working through all three, capture the server logs and the exact property and column YAML, then contact [Nextedy support](https://support.nextedy.com/support/tickets/new).
</Note>

### Dynamic Value Expressions

Client-side expressions fail silently if the context property is not available. Verify:

1. You are using the `() =>` prefix (not `$context`, which is for model constraints only)
2. The context property is available at the location where you are using it (see the availability table above)
3. Property names match your data model exactly (case-sensitive)

***

## Verification

After saving your YAML configuration and reloading the sheet:

1. **Server-rendered property**: You should now see the computed value in the column. Edit the underlying work item fields and reload -- the computed value updates to reflect the changes
2. **Dynamic formula**: You should now see the calculated value appear. If using `formula`, verify the value is persisted by checking the work item in Polarion
3. **Render/display**: You should now see formatted output in the cell without any data modification

If you see `#SERVER_RENDER_ERROR` in a column, refer to [Debug Template Errors](/powersheet/guides/server-rendering/debug-template-errors) for troubleshooting steps.

## See Also

* [Use Velocity Templates](/powersheet/guides/server-rendering/use-velocity-template) -- write and test Velocity template expressions for server rendering
* [Access Polarion Services](/powersheet/guides/server-rendering/access-polarion-services) -- use platform services like `$trackerService` in your templates
* [Debug Template Errors](/powersheet/guides/server-rendering/debug-template-errors) -- diagnose and fix server rendering failures
* [Configure Dynamic Expressions](/powersheet/guides/sheet-configuration/configure-dynamic-expressions) -- full guide to `() =>` expressions in sheet configuration
* [Add a Custom Property](/powersheet/guides/data-model/add-custom-property) -- add standard (non-computed) properties to entity types
* [Configure a Formatter](/powersheet/guides/sheet-configuration/configure-formatter) -- apply conditional styling with formatter expressions

<LastReviewed date="2026-07-02" />
