➕ Calculation Property
Calculation properties allow you to use existing properties defined on blueprints, either directly or by using relations and mirror properties, in order to create new properties by using the jq processor for JSON.
Starting March 30, 2026, persistent calculation properties were introduced, which have various benefits compared to the legacy calculation properties.
Port accounts created after March 30, 2026 have persistent calculation properties by default.
If your account was created before this date, you can enable persistent calculation properties for your organization.
Usage
Calculation properties can be used to:
- Filter, select, slice, and concatenate data from an existing property.
- Create math equations or modifications. For example, calculate required disk storage by specifying page size and number of pages needed.
- Merge complex properties, including deep-merge and overriding.
Use-case examples
- Construct custom URLs based on templates, for example:
https://slack.com/ + {my_parameter}.https://datadog.com/ + {my_parameter}.https://launchdarkly.com/ + {my_parameter}.
- Merge service configuration templates to create a real service config.
- Calculate the number of code owners.
In this live demo example, we can see the Slack Notifications calculation property. 🎬
Definition
- API
- Terraform
- Pulumi
The calculationProperties key is a top-level key in the JSON of an entity (similar to identifier, title, properties, etc..)
You can access properties as part of the calculation by using .properties
{
"calculationProperties": {
"myCalculationProp": {
"title": "My calculation property",
"type": "string",
"calculation": ".properties.myStringProp + .properties.myStringProp"
}
}
}
Check out Port's API reference to learn more.
resource "port_blueprint" "myBlueprint" {
# ...blueprint properties
calculation_properties {
identifier = "myCalculationProp"
title = "My calculation property"
type = "string"
calculation = ".properties.myStringProp + .properties.myStringProp"
}
}
- Python
- TypeScript
- JavaScript
- GO
"""A Python Pulumi program"""
import pulumi
from port_pulumi import Blueprint,BlueprintPropertiesArgs,BlueprintCalculationPropertiesArgs
blueprint = Blueprint(
"myBlueprint",
identifier="myBlueprint",
title="My Blueprint",
properties=BlueprintPropertiesArgs(
# blueprint properties
),
calculation_properties={
"myCalculation": BlueprintCalculationPropertiesArgs(
title="My calculation property", calculation=".properties.myStringProp + .properties.myStringProp", type="string",
)
},
)
import * as pulumi from "@pulumi/pulumi";
import * as port from "@port-labs/port";
export const blueprint = new port.Blueprint("myBlueprint", {
identifier: "myBlueprint",
title: "My Blueprint",
properties: {
// blueprint properties
},
calculationProperties: {
myCalculation: {
title: "My calculation property",
calculation: ".properties.myStringProp + .properties.myStringProp",
type: "string",
},
},
});
"use strict";
const pulumi = require("@pulumi/pulumi");
const port = require("@port-labs/port");
const entity = new port.Blueprint("myBlueprint", {
title: "My Blueprint",
identifier: "myBlueprint",
properties: {
// blueprint properties
},
calculationProperties: {
myCalculation: {
title: "My calculation property",
calculation: ".properties.myStringProp + .properties.myStringProp",
type: "string",
},
},
});
exports.title = entity.title;
package main
import (
"github.com/port-labs/pulumi-port/sdk/v2/go/port"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
blueprint, err := port.NewBlueprint(ctx, "myBlueprint", &port.BlueprintArgs{
Identifier: pulumi.String("myBlueprint"),
Title: pulumi.String("My Blueprint"),
// blueprint properties..
CalculationProperties: port.BlueprintCalculationPropertiesMap{
"myCalculation": port.BlueprintCalculationPropertiesArgs{
Title: pulumi.String("My calculation property"),
Calculation: pulumi.String(".properties.myStringProp + .properties.myStringProp"),
Type: pulumi.String("string"),
}
},
})
ctx.Export("blueprint", blueprint.Title)
if err != nil {
return err
}
return nil
})
}
Supported types
- Basic
- Format
- Spec
Calculation properties support the following output types: string, number, object, array, and boolean. For example:
{
"calculationProperties": {
"myCalculationProp": {
"title": "My calculation property",
"type": "my_output_type",
"calculation": ".properties.myStringProp + .properties.myStringProp"
}
}
}
Calculation properties support the following output formats: yaml, team, user, ipv6, and url. For example:
{
"calculationProperties": {
"myCalculationProp": {
"title": "My calculation property",
"type": "string",
"format": "user",
"calculation": ".properties.user"
}
}
}
Calculation properties support the following output specs: markdown, open-api and async-api. For example:
{
"calculationProperties": {
"myCalculationProp": {
"title": "My calculation property",
"type": "string",
"format": "url",
"spec": "embedded-url"
"calculation": ".properties.text"
}
}
}
Using meta properties in calculation properties
It is possible to use meta properties as template values for calculation properties.
For example, if you want to concatenate a template URL (for example https://datadog.com) with the identifier meta property:
Given the following notification-service entity:
{
"identifier": "notification-service",
"title": "Notification Service",
"properties": {
...
},
}
And the following calculation property definition for the blueprint:
{
"calculationProperties": {
"monitorUrl": {
"title": "Monitor url",
"type": "string",
"format": "url",
"calculation": "'https://datadog.com/' + .identifier"
}
}
}
The value of the property monitorUrl will be https://datadog.com/notification-service
Using mirror properties in calculation properties
It is possible to use mirror properties as template values for calculation properties.
For example, if an entity has a mirror property called owningSquad:
"mirrorProperties": {
"owningSquad": {
"path": "microservice-to-squad.$title"
}
}
A calculation property that links to the slack channel of the squad can be:
"owning_squad_slack": {
"title": "Owning Squad Channel",
"calculation": "'https://slack.com/' + .properties.owningSquad",
}
Calculation properties cannot be used as template values for other calculation properties.
Colorized calculation properties
You can colorize calculation properties according to their value, by adding a colorized key with the value true to the calculation property object. You can also add a colors key to specify the colors of the different values, otherwise, the colors will be chosen automatically for you.
For example, if you want to colorize a calculation property called status-calculation with the values OK, WARNING, and CRITICAL:
"properties":{
"status":{
"type": "string"
},
},
"calculationProperties": {
"status-calculation": {
"title": "Status",
"type": "string",
"calculation": ".properties.status",
"colorized": true,
"colors": {
"OK": "green",
"WARNING": "yellow",
"CRITICAL": "red"
}
}
}
Parameters that contain special characters (for example: -) or start with a digit (for example: @/#/$/1/2/3) should be surrounded with single quotes.
"properties":{
"prop-with-special-char":{
"type": "string"
},
},
"calculationProperties": {
"myCalculatedProp": {
"title": "My Calculated Property",
"type": "string",
"calculation": ".properties.'prop-with-special-char'",
}
}
Examples
Refer to the calculation property examples page.
Persistent calculation properties
With persistent calculation properties, values are computed and stored in the background, as opposed to being computed on-request.
Benefits compared to legacy calculation properties:
- Faster entities table: Loading the entities table is much faster because calculations are not run on each request (for example, up to 10 times faster for a blueprint with 100,000 entities and 3 calculation properties).
- Filter by calculation properties: You can filter entities by calculation properties in search and the API—something that was not possible before.
- Richer visualizations: You can create line charts on calculation properties and use drill-down pie charts based on calculation properties.
How to enable the feature
Port accounts created after March 30, 2026 have persistent calculation properties enabled by default. The steps below apply only to existing users who have not yet enabled this feature.
Before enabling, review the breaking changes below, or use the helper script to scan your organization automatically.
- Go to your Port application, click on the ... button in the top right corner, and select Credentials.
- Click on the Generate API token button, and copy the generated token.
curl -L -X POST 'https://api.getport.io/v1/blueprints/persistent-calculation-properties/register' \
-H 'Authorization: <YOUR_BEARER_TOKEN>'
Identify calculation properties to review
Before you enable the feature, you can run a helper script that scans your Port organization for calculation properties that may need the updates described in Breaking changes below.
The script is read-only: it only reads data from Port and does not modify blueprints, entities, or any other catalog data.
The persistent calculation properties script in the port-labs/script-examples repository:
- Connects to your Port organization.
- Checks whether persistent calculation properties are already enabled.
- Scans blueprint calculation properties for the same breaking patterns (relative
nowin JQ, and.relations.<name>.titleor.relations.<name>.identifier). - Generates an HTML report under
output/(for exampleoutput/index.html) with summary statistics and a table of properties that need review.
See the repository README for prerequisites, config.json, and how to run npm start.
Breaking changes
When moving to persistent calculation, two behaviors change and may require updates to your calculation properties.
If you have calculation properties that use relative date (now) or relation titles (e.g. .relations.relationName.title), review the items below and update them before enabling the feature.
Change 1: Relative date (now in JQ)
Calculations that use the now JQ function (relative to the current time) are no longer evaluated at request time. Their values are accurate to roughly an hour, not to the second or minute.
What you can do:
- If roughly hour-level accuracy is enough for your use case, no change is needed.
- If you need second- or minute-level accuracy, do not compute the relative date inside the calculation property. Store only the target date in the property (e.g. from entity data), and compute the relative value (e.g. "minutes ago") where you use the property—for example in the UI or in a workflow.
Change 2: Relation titles (.relations.<name>.title)
With persistent calculation, the evaluation context does not use the Search entities attach_title_to_relation behavior. So JQ that expects relation values to be objects with .title (e.g. .relations.microservice.title) will break, because in this context relations are string or array of strings (identifiers only). For the two response shapes, see the attach_title_to_relation parameter in the advanced search docs.
What you can do:
- If you need the related entity's title inside the JQ, create a mirror property for the title (e.g.
path: "relationName.$title") and reference that property in your calculation (e.g..properties.myRelationTitle) instead of.relations.relationName.title. - Otherwise, write the JQ for identifier-only relations (string or array of strings).
Rollback the feature
If you need to disable persistent calculation and return to on-request evaluation, send a single POST request to the unregister endpoint. It is a straightforward switch—nothing else in your catalog or blueprints changes beyond how calculation properties are evaluated.
The request matches How to enable the feature, but use the unregister path instead.
curl -L -X POST 'https://api.getport.io/v1/blueprints/persistent-calculation-properties/unregister' \
-H 'Authorization: <YOUR_BEARER_TOKEN>'
Use the same bearer token as in How to enable the feature.