Link Settings
A link expresses "I have a runtime relationship with this component". Every link is
{target, settings} — a component reference plus an optional flat map of values. The agent reads
the settings to derive security-group rules, load-balancer registrations, IAM grants, injected
environment, and more.
This page is the settings contract for every link type the platform handles. For the concepts — how links differ from dependencies and parameters, how the two-phase resolver works, and what a custom agent must implement — see Component Links.
The link format is always generic: target plus settings. There are no specialised or typed link
schemas on the wire — port, protocol, consumer group, access level and mount path are all keys in
the settings map. SDKs wrap this in typed linkToXxx() helpers or typed settings shapes applied
with satisfies, but the wire contract never changes.
Security group membership
A compute component (VM, ECS task, EKS node, …) links to a SecurityGroup to declare membership.
No settings. The presence of the link is the only signal, and no dependency on the security group is required or correct.
Managed security-group traffic rules
When compute component A links to compute component B, the agent derives egress rules on A's managed security group and ingress rules on B's.
| Setting | Type | Required | Description |
|---|---|---|---|
fromPort | number | yes | Start of the port range. A link without it is skipped. |
toPort | number | no | End of the port range. Defaults to fromPort. |
protocol | string | no | tcp (default), udp or icmp. |
The managed group is named fractal-mgd-{componentId}, tagged fractal-managed=true, and its id is
published as the managedGroupId output field. Do not attempt to manage rules on it directly —
the managed group is created and owned by the agent — never manage its rules directly.
Load balancer
Load balancers use two link directions with different settings.
Target registration — LB links to compute
| Setting | Type | Required | Description |
|---|---|---|---|
instanceId | string | yes (EC2 targets) | EC2 instance id. |
ip | string | yes (ECS / EKS / IP targets) | IP address of the target. |
vpcId | string | yes | VPC the target lives in. |
tgPort | number | no | Port on the target. Default 80. |
availabilityZone | string | no | AZ, for zone-aware routing. |
loadBalancerArn | string | yes (ALB target) | ARN of the upstream ALB. |
hcProtocol | string | no | Health check protocol. Default HTTP. |
hcPath | string | no | Health check path. Default /. |
hcIntervalSeconds | number | no | Health check interval. Default 30. |
Listener declaration — a component links to the LB
A component that logically drives the load balancer (a DNS or gateway component) links to it and declares the frontend listener.
| Setting | Type | Required | Description |
|---|---|---|---|
listenerPort | number | yes | Frontend port, e.g. 443. |
listenerProtocol | string | yes | HTTP, HTTPS, TCP, … |
targetComponentId | string | yes | Id of the linked backend component to forward to. |
Consumer → RelationalDatabase
Declares "I use this database". The agent grants the consumer its own database role scoped by
access, and injects vendor-neutral connection environment.
| Setting | Type | Required | Description |
|---|---|---|---|
access | 'read-write' | 'read-only' | yes | Scope of the granted database role. |
access is the canonical key and has no default — a link without it is rejected rather than
guessed at, because read-only silently breaks a writer and read-write silently over-grants a reader.
Two older spellings are still accepted, because the authoring surface, not the author, decided which
one a link carries:
| Alias key | Accepted values | Where it comes from |
|---|---|---|
accessMode | read, write, readWrite | The catalogue's shared Storage.*.RelationalDatabase link declaration — so UI-authored links. |
roleName | reader, data_reader, writer, data_writer, admin | Blueprints written against the Azure Flexible Server path. |
access wins when more than one is present.
Injected into the consumer: DB_HOST, DB_PORT, DB_NAME, DB_USERNAME, DB_PASSWORD_REF.
Connection facts are published by the database as output fields, not carried on the link. The raw
password never enters output fields — DB_PASSWORD_REF carries only a secret-store reference the
runtime resolves at launch.
Compute → ObjectStorage
Declares "I use this bucket". The agent ensures the consumer has an identity (creating and attaching
one when absent — GCP service account, AWS instance profile, Azure managed identity), grants that
identity a bucket role scoped by access, and publishes the bucket URI to the consumer.
| Setting | Type | Required | Description |
|---|---|---|---|
access | 'read' | 'write' | 'read-write' | yes | Scope of the granted storage role. |
Role mapping is vendor-agnostic and never a broad scope:
access | AWS | Azure | GCP |
|---|---|---|---|
read | s3:GetObject + ListBucket | Storage Blob Data Reader | objectViewer |
write | s3:PutObject | Storage Blob Data Contributor | objectCreator |
read-write | both | Storage Blob Data Contributor | objectAdmin |
Workload / DataProcessingJob → MessagingEntity
Declares "I publish to / subscribe from this topic or queue". The messaging agent grants the source the right IAM/ACL on the entity and wires consumer-side parameters.
| Setting | Type | Required | Description |
|---|---|---|---|
access | 'publish' | 'subscribe' | 'publish-subscribe' | yes | Direction of the relationship. |
consumerGroup | string | no | Consumer group / subscription identifier. Only meaningful when access includes subscribe. |
startingPosition | string | no | start, end, or an ISO timestamp. |
The schema is identical for both source types.
DataProcessingJob → Datalake
Declares "I read from / write to this lake for the given purpose". The agent injects the
corresponding URI into the job runtime (LAKE_RAW_URI, LAKE_CURATED_URI, LAKE_CHECKPOINT_URI).
Multiple links per job are allowed and may target different lakes.
| Setting | Type | Required | Description |
|---|---|---|---|
purpose | 'raw' | 'curated' | 'checkpoint' | yes | Ingestion zone, processed outputs, or streaming state. |
path | string | no | Sub-path within the lake. The agent composes <lake-uri>/<path>. |
ComputeCluster → EventHub instance
Azure only. Wires EventHub connection strings into the Spark configuration via Databricks secret scopes.
| Setting | Type | Required | Description |
|---|---|---|---|
keyVaultSecretName | string | yes | Name of the management Key Vault secret holding the EventHub connection string. |
consumerGroup | string | no | EventHub consumer group. Default $Default. |
startingPosition | string | no | start, end (default), or an ISO timestamp. |
Consumer → IdentityProvider
Declares "I am an OAuth client of this identity provider". Each such link provisions exactly one app client on the pool/tenant. Guardrails on the identity provider Component (MFA, password policy, allowed OAuth flows) cap what any link's client may request.
| Setting | Type | Required | Description |
|---|---|---|---|
clientType | 'web' | 'spa' | 'machine' | yes | web = confidential (login flow + secret); spa = public; machine = client-credentials, no redirect. |
redirectUris | string[] | yes for web / spa | OAuth callback URLs. |
logoutUris | string[] | no | Post-logout redirect URLs. Browser flows only. |
scopes | string[] | no | Requested OAuth scopes. |
Injected into the consumer: OIDC_ISSUER_URI, OIDC_CLIENT_ID, OIDC_JWKS_URI, OIDC_SCOPES,
and — for confidential clients — OIDC_CLIENT_SECRET_REF. The raw client secret is never placed in
output fields; it lives in the vendor secret store and the reference is resolved at launch.
Consumer → Unmanaged
Declares "I consume this external service". The agent grants the consumer read access to the component's referenced secret and injects the config plus a secret reference — never the raw secret.
| Setting | Type | Required | Description |
|---|---|---|---|
envPrefix | string | no | Prefix for the injected config and secret reference. Defaults to the target component's id. |
Environment-secret references
Any component parameter or link setting value may reference an environment secret by short name instead of carrying the raw value.
// Define once on the environment:
env.withSecret({shortName: 'svc-token', displayName: 'Service token', value: TOKEN});
// Reference from a parameter …
UnmanagedAi({secret: secretRef('openai-api-key')});
// … or from a link setting:
link(vm, svc, {token: secretRef('svc-token')});
The wire shape is the tagged value {"$envSecret": "<shortName>"}. The agent resolves the reference
from the environment secret store at reconciliation time — parameters through the short-name
resolver, link settings through the link framework before handlers read them — and never writes the
raw value into output fields. Secrets always surface downstream as a *_REF reference.
Use this for every secret an external component or a link needs. The raw value stays in the secret store.
Link resolution phases
Link-derived work is segregated so that creating a machine is never conflated with deploying software onto it:
- Component creation — a VM is created with its identity (created and associated at create time when the VM has a configured identity or any injectable link).
- Link resolution — a generic hook invoked after the component is Active, every patrol cycle,
idempotent. For a VM it assigns roles and permissions to the VM identity: a scoped object-storage
role from the link's
access, read on a linkedUnmanagedcomponent's referenced secret. Grants are diffed against prior state held in the VM'slinkGrantsoutput field, so removing a link revokes the access. No environment is delivered to the box in this phase. - Workload deployment — the workload on the VM consumes the resolved values (bucket URI,
*_SECRET_REF) as its runtime environment.
Anti-patterns
- Using a dependency when you mean a link. If A only needs B to exist, that is a dependency. If A needs to read B's URL or secret, that is a link.
- Adding a dependency alongside a membership link. Security-group and network-policy membership needs the link only.
- Putting connection facts on the link. Hosts, ports, URIs, client ids and secrets are published by the target as output fields and injected downstream. A link carries intent, not data.
- Putting a raw secret in a parameter or setting. Use
secretRefand an environment secret.