Skip to main content

Server operation

Dex Server exposes the FlowService API, coordinates durable Flow execution, and serves the Dex Web API. Run it as a managed production service with explicit configuration, health checks, and access control.

Local development

For a local stack, install dexcli and run:

brew install superdurable/tap/dexcli
dexcli dev

This starts Dex Server and Dex Web for local use. See the CLI README for options.

Production deployment shape

  • Run Dex Server as a managed service with readiness and liveness checks.
  • Give application clients and Workers a stable, authenticated server address.
  • Configure durable Blob Store storage for large payloads.
  • Configure a MySQL or PostgreSQL Custom Attribute Store when you need searchable projections.
  • Publish Dex Web only through your organization’s authenticated access path.
  • Collect logs and Prometheus metrics from every Server instance.

Deploy Server configuration and application Worker changes independently. A Worker release can change Flow behavior; use the versioning process in Application operation before retiring a definition.

Server and SDK protocol compatibility

Dex Server and each SDK release declare inclusive protocol intervals. A Worker can start when those intervals overlap. It negotiates the highest common protocol, then synchronizes Attribute indexes, then binds WorkerService. The Server and SDK artifact versions are diagnostic and do not decide compatibility.

When upgrading a deployment that predates GetServerInfo, upgrade the Server first. Older Servers do not implement the check and new Workers reject them. After that first upgrade, a new SDK can use an older Server when it retains the older protocol, and a new Server can use an older SDK while their intervals still overlap.

A breaking Server release raises its minimum protocol. Stop old Workers and their traffic before that Server upgrade. Upgrade the Server and SDKs in a maintenance window, then restart traffic. Alternatively, use isolated blue and green environments so deployments with disjoint intervals never communicate. Running Workers do not renegotiate after a Server upgrade, so stop them explicitly before a breaking change.

Protocol compatibility covers the Worker-to-Server API only. It does not replace the compatibility rules for open Flows, including Flow type names, Step graphs, and persisted payloads.

Server components

The dex-server image starts Dex Web, API, and Interpreter in one process by default. The container listens on port 8801 for FlowService and port 8802 for Dex Web. Publishing either port remains an explicit deployment decision.

Use the services startup option to run any non-empty combination. Separate components when they need different replica counts or resource limits:

dex-server start --services web
dex-server start --services api
dex-server start --services interpreter
dex-server start --services web,api

An Interpreter-only deployment must set interpreter.interpreterActivityConfig.internalServiceTarget to the API service. A Web-only deployment does not connect to Temporal or Cadence. It starts before its API upstream is available, so /healthz reports only Web process health. Web API requests return an upstream error until FlowService is available.

Configuration

Server configuration is YAML and typed Go configuration. The production configuration is separate from the limited flags accepted by dexcli dev. Keep configuration in your approved secret-management and deployment system, not in an application image.

The Blob Store section is named blobStore. Its entries use BlobStoreConfigEntry. The former externalStorage key is not accepted.

Configure the Web listener and API upstream in the web section:

web:
bindAddress: 0.0.0.0
port: 8802
flowServiceTarget: dex-api:8801
flowRenderingDirectory: ""

The bind address defaults to all interfaces and the port defaults to 8802. An empty flowServiceTarget uses localhost and the configured API port. The Web connection is plaintext gRPC and uses api.grpcMaxMessageBytes, so keep it on a trusted network path.

Blob Store

Configure a durable store before allowing payloads that exceed inline limits. Use separate credentials and least-privilege policies for each environment. Monitor write and read failures, then test a recovery procedure that can still read existing objects after a credential rotation.

Dex keeps payloads through 100 bytes inline by default. A 101-byte string or encoded object is offloaded. Set blobStore.thresholdInBytes to override the default. The comparison uses only the payload size, not the resulting reference size.

blobStore:
thresholdInBytes: 100
objectIdLength: 10
asyncStepInputSnapshotsEnabled: true
supportedStorages:
- status: active
storageId: p1
storageType: s3

Keep storageId short because every offloaded value stores it in durable history. For example, use p1 instead of production1 when the shorter name is still operationally clear.

Blob references are opaque application values. Their wire forms are:

String: <storageId>|<base36DayOffset>/<objectId>
Object: <storageId>|<base36DayOffset>/<objectId>

Example: p1|c/ab3de7kp2x

The Value arm distinguishes String and Object references. An Object Blob stores the complete EncodedObject, including its json, raw, or custom encoding. The reference keeps the storage ID and UTC write date, but omits the Flow ID and encoding. Dex obtains the owning Flow ID from trusted request or Worker context. The physical object path is:

<namespace>/<YYMMDD>$<escapedFlowId>/<objectId>

Example: default/260913$coding-session--c08256c4/ab3de7kp2x

The reference date is the lowercase Base36 day offset from September 1, 2026 UTC. It has no leading zeros: 0 is September 1, 2026, c is September 13, 2026, and 10 is October 7, 2026. The physical path retains YYMMDD, whose two-digit year represents 2000 through 2099.

Common Flow ID characters remain readable in the physical path. Dex percent-escapes characters that are unsafe in object-key path segments. For example, SubFlow:parent-step-0 becomes SubFlow%3Aparent-step-0. Run IDs and Step execution IDs in input-snapshot paths remain Base64URL encoded.

Internal references belong to exactly one Flow. Dex rehydrates and rewrites a reference before it crosses a Flow boundary. The destination receives an inline value or a new object under its own Flow prefix. Deleting the source Flow therefore cannot corrupt the destination Flow. Public APIs reject client-supplied internal references.

Object IDs use deterministic lowercase Base36 characters. Retries with the same invocation ID and stored bytes overwrite the same object instead of creating duplicates. Object stored bytes include the encoding. Dex does not perform a read-before-write, conditional create, or collision retry. blobStore.objectIdLength defaults to 10. Zero selects that default, negative values are invalid, and positive values are accepted without a protocol-defined range. Every Server writing the same Blob Store namespace must use the same value, and the setting must not change while those Servers are running. Readers accept any non-empty lowercase Base36 ID, so a deployment can change the configured length during a coordinated restart.

Ten Base36 characters provide about 51.7 bits. Within one Flow and one UTC day, the approximate probability of at least one collision is 1.4 × 10⁻⁸ for 10,000 objects, 1.4 × 10⁻⁶ for 100,000 objects, and 1.4 × 10⁻⁴ for 1,000,000 objects. Use 10 for ordinary deployments. Use 12 or 16 for high-throughput Flows. A length of 50 can represent the full SHA-256 value. Longer values add leading zeros but no additional entropy.

Cleanup keeps the UTC date at the start of each Flow prefix. It lists prefixes in lexical pages, decodes the escaped Flow and optional Run, and deletes the whole prefix only after the execution no longer exists. Continue listing with the returned continuation token; no manifest is involved.

Async Step input snapshots are enabled by default when Blob Store is enabled. They retain the exact inputs sent to successful ASYNC local Step methods so semantic history can show them. The snapshot is independent of the payload offload threshold and is not required for Flow execution, retry, or recovery. Set blobStore.asyncStepInputSnapshotsEnabled to false to skip that optional history cost. When disabled, ASYNC local completion events report their input as unavailable. SYNC methods and ASYNC methods that fall back to a regular Activity continue to obtain input from backend history.

The optional blobStore.blobCache caches S3-backed Attribute objects. A non-empty directory enables it and must belong to one Server process. Its default budget is 1 GiB. Oversized or rejected objects bypass the cache and continue to the source Blob Store. A corrupt entry is invalidated and refilled; initialization, recovery, and disk I/O errors are Server errors. Local Blob Store objects and Step-event input snapshots do not use this cache.

Stream Store

Configure streamStore to enable best-effort Streams. Use the memory backend for one local Server process. Use Redis 7 or newer when multiple Server processes must share retained messages. Redis requires redisURL. Keep Redis on noeviction so capacity pressure becomes a visible Stream write failure.

maxMessageBytes defaults to 100 KiB per serialized message. maxReadMessages caps one reverse listing page, defaults to 1000, and must be positive. Stream capacity remains part of each registered Stream definition. The remaining Stream Store settings control approximate charging, trim watermarks, trim batches, leases, and worker concurrency.

Custom Attribute Store

Use a Custom Attribute Store when a relational projection supports operational searches or business reporting. Follow the schema and retry requirements in Custom Attribute Store. Treat its database, credentials, migrations, and backups as production dependencies of the Dex deployment.

Dex Web access control

Dex Web can reveal Flow inputs, outputs, Attributes, and Worker stack traces. Place it behind TLS and an authentication-enforcing reverse proxy or gateway. Authorize production access by role, and restrict it to operators who need to inspect Flow data.

Do not expose Dex Web or the FlowService API directly to the public Internet. Protect server and Worker endpoints with network policy, authenticated transport, and narrowly scoped service identities. Audit access to production Flow details according to your data-handling policy.