Dapr Building Blocks
The optional sidecar runtime behind Redis, Pub/Sub & more
Dapr is the runtime adapter layer Nucleus can sit on instead of talking to infrastructure directly. When you flag withDapr on Redis (or wire a Dapr pub/sub component), the framework routes through a Dapr sidecar and gains its full set of portable building blocks — state, pub/sub, service invocation, secrets, bindings, distributed locks, cryptography, configuration and workflows — without binding your code to a specific vendor.
Internally this is the DaprManager (exported as the daprManager singleton), which owns a single DaprConnectionManager and exposes a typed sub-client for every building block — daprManager.state, .pubsub, .binding, .secret, .config, .invoke, .lock, .crypto, .workflow. It is entirely opt-in: with Dapr off, Nucleus connects to Postgres and Redis directly and none of this is in the path. This page documents each sub-client below, except the pub/sub primitive — daprManager.pubsub.publish / publishBulk (default component pubsub-rabbitmq) — which is covered on the dedicated Pub/Sub page. Beyond that, nothing about how Nucleus reaches infrastructure is a black box.
Connection & the sidecar#
Dapr runs as a sidecar next to your app. The manager connects to it over HTTP (default) or gRPC, lazily and once, and reuses that client for every call.
host / port / endpointenv: DAPR_HOST, DAPR_HTTP_PORT, …OptionalDefaults to 127.0.0.1:3500. Reads DAPR_HOST / DAPR_HTTP_PORT, or a full DAPR_HTTP_ENDPOINT when the sidecar is elsewhere. An optional DAPR_API_TOKEN authenticates app→sidecar calls. Note: the default exported daprManager speaks HTTP; the protocol is a code-level DaprConnectionOptions setting (no env var flips it), so DAPR_GRPC_ENDPOINT is honored only if you construct your own manager with communicationProtocol=GRPC — it has no effect on the default singleton. Request payload size is likewise bounded by maxBodySizeMb — another code-level DaprConnectionOptions setting with no env var (default 4 MB, passed into the DaprClient and reported by getClientConfig) — so oversized state saves or pub/sub messages require constructing your own manager with a higher maxBodySizeMb.
lazy connect + statusDISCONNECTED → CONNECTING → CONNECTEDOptionalgetClient() auto-connects on first use and reuses the client thereafter. A single-flight connection promise prevents thundering-herd reconnects, and every connect is bounded by a timeout so a missing sidecar fails fast instead of hanging.
health checkshealthCheck() / isConnected()OptionalhealthCheck() invokes the sidecar's healthz endpoint (204 → healthy) and reports the dapr-version header; isConnected() / getConnectionStatus() expose the live connection state, and getClientConfig() returns the resolved host/port/protocol without leaking the API token.
State & configuration#
The state store is the building block Redis uses in Dapr mode — a portable key/value API with bulk, query and transactional operations.
statestate.save / get / deleteOptionalSave, read and delete keys against a state store (default statestore-redis). state.getBulk reads many keys at once, state.query runs filter/sort/page queries, and state.transaction commits multiple operations atomically.
configurationconfig.get(keys, store)OptionalReads dynamic configuration values from a Dapr config store (default configstore-redis) — useful for runtime flags that live outside your config.nucleus.json. config.subscribeWithKeys streams live updates for the watched keys.
Service invocation & bindings#
Reach other services and external systems through the sidecar, with discovery, retries and mTLS handled for you.
service invocationinvoke.invoke(appId, method, httpMethod, data)OptionalCall another Dapr app by its appId — the same appId primitive each Nucleus service declares — without knowing its address. The mesh resolves it, securing the hop with mTLS.
output bindingsbinding.invoke(name, operation, data)OptionalTrigger an external resource (queues, blob stores, SMTP, cron, cloud services) through a configured binding component, keeping vendor SDKs out of your code.
Secrets & cryptography#
Pull secrets from a managed store and perform envelope encryption without holding key material in the app.
secretssecret.get(key, options?, store?) / secret.getBulk(options?, store?)OptionalFetch one secret or the whole store from a secret-store component (default secretstore — Vault, cloud secret managers, K8s secrets) — so credentials never live in the image or config file.
cryptographycrypto.encrypt / decrypt(bytes, options)OptionalEnvelope encryption against a crypto component (options carry componentName + keyName): the key stays in the provider, the app only sends/receives bytes. crypto.encryptString / decryptString wrap the same flow for text. Useful for field-level encryption beyond the database layer.
Distributed locks & workflows#
Coordinate across replicas and run durable, long-lived processes.
distributed lockslock.lock / unlock(store, resourceId, owner, …)OptionalAcquire a named lock with an owner and an expiry (options.expiryInSeconds) so only one replica runs a critical section (a backup, a migration, a scheduled job). lock.lock returns { success } rather than throwing, so callers branch cleanly.
workflowsworkflow.start / get / terminate / pause / resume / raiseEvent / purgeOptionalDrive Dapr's durable workflow engine: start an instance, query it, pause/resume, raiseEvent to send external events into it, terminate or purge it — for orchestrations that must survive restarts.
Related sections