Introduction
The Dapr Client allows you to communicate with the Dapr Sidecar and get access to its client facing features such as Publishing Events, Invoking Output Bindings, State Management, Secret Management, and much more.
For LLM interactions, use client.conversation.converse(request). The Conversation guides cover setup, message history, structured output, caching, token usage, and tool calling with JavaScript SDK 3.19.0 or later.
Pre-requisites
- Dapr CLI installed
- Initialized Dapr environment
- Latest LTS version of Node.js or greater
Installing and importing Dapr’s JS SDK
- Install the SDK with
npm:
npm i @dapr/dapr --save
- Import the libraries:
import { DaprClient, DaprServer, HttpMethod, CommunicationProtocolEnum } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server
// HTTP Example
const client = new DaprClient({ daprHost, daprPort });
// GRPC Example
const client = new DaprClient({ daprHost, daprPort, communicationProtocol: CommunicationProtocolEnum.GRPC });
Running
To run the examples, you can use two different protocols to interact with the Dapr sidecar: HTTP (default) or gRPC.
Using HTTP (default)
import { DaprClient } from "@dapr/dapr";
const client = new DaprClient({ daprHost, daprPort });
# Using dapr run
dapr run --app-id example-sdk --app-protocol http -- npm run start
# or, using npm script
npm run start:dapr-http
Using gRPC
Since HTTP is the default, you will have to adapt the communication protocol to use gRPC. You can do this by passing an extra argument to the client or server constructor.
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";
const client = new DaprClient({ daprHost, daprPort, communicationProtocol: CommunicationProtocolEnum.GRPC });
# Using dapr run
dapr run --app-id example-sdk --app-protocol grpc -- npm run start
# or, using npm script
npm run start:dapr-grpc
Environment Variables
Dapr Sidecar Endpoints
You can use the DAPR_HTTP_ENDPOINT and DAPR_GRPC_ENDPOINT environment variables to set the Dapr
Sidecar’s HTTP and gRPC endpoints respectively. When these variables are set, the daprHost
and daprPort don’t have to be set in the options argument of the constructor, the client will parse them automatically
out of the provided endpoints.
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";
// Using HTTP, when DAPR_HTTP_ENDPOINT is set
const client = new DaprClient();
// Using gRPC, when DAPR_GRPC_ENDPOINT is set
const client = new DaprClient({ communicationProtocol: CommunicationProtocolEnum.GRPC });
If the environment variables are set, but daprHost and daprPort values are passed to the
constructor, the latter will take precedence over the environment variables.
Dapr API Token
You can use the DAPR_API_TOKEN environment variable to set the Dapr API token. When this variable
is set, the daprApiToken doesn’t have to be set in the options argument of the constructor,
the client will get it automatically.
General
Increasing Body Size
You can increase the body size that is used by the application to communicate with the sidecar by using aDaprClient’s option.
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";
// Allow a body size of 10Mb to be used
// The default is 4Mb
const client = new DaprClient({
daprHost,
daprPort,
communicationProtocol: CommunicationProtocolEnum.HTTP,
maxBodySizeMb: 10,
});
Proxying Requests
In JavaScript SDK 3.19.0, client.proxy.create() is unsupported for both HTTP and the gRPC ConnectRPC transport and rejects when called. Use client.invoker.invoke() for Dapr service invocation.
For native protobuf services, use your generated gRPC client connected to the Dapr sidecar with dapr-app-id metadata. See native gRPC services and streaming and the runtime gRPC proxying guide.
Building blocks
The JavaScript Client SDK allows you to interface with all of the Dapr building blocks focusing on Client to Sidecar features.
Search API
Use client.search to manage indexes and index, retrieve, delete, and query JSON documents over HTTP or gRPC. Requires Dapr runtime 1.19 or later and JavaScript SDK 3.19.0 or later.
See the Search how-to guide for a complete example, and Search client usage for method signatures, query options, write acknowledgements, cancellation, and errors.
Jobs API
Use client.jobs to schedule, retrieve, and delete jobs with JavaScript SDK 3.19.0 or later. See the Jobs how-to guide and client usage guidance for scheduling options, payloads, runtime compatibility, and error handling.
Invocation API
For JavaScript SDK 3.19.0 or later, see the service invocation overview for HTTP and gRPC capabilities.
Invoke a Service
import { DaprClient, HttpMethod } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient({ daprHost, daprPort });
const serviceAppId = "my-app-id";
const serviceMethod = "say-hello";
try {
const response = await client.invoker.invoke(
serviceAppId,
serviceMethod,
HttpMethod.POST,
{ hello: "world" },
{ headers: { "X-User-ID": "123" } },
);
console.log(response);
} finally {
await client.stop();
}
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
Follow calling services for a runnable client and server setup, other verbs, query parameters, namespaces, and non-Dapr endpoints. See configuration and usage for serialization and errors. Custom request headers are forwarded by the HTTP invoker, not the gRPC invoker.
State Management API
Use client.state to access configured state stores over HTTP or gRPC. The state management guides cover JavaScript SDK 3.19.0 or later, including bulk deletion, ETags, state options, TTL, transactions, serialization, and protocol-specific errors.
Save, Get and Delete application state
Follow How to: Manage state for a runnable example with component configuration, save/get/delete, bulk reads and deletes, conditional updates, and transactions.
HTTP save, delete, and deleteBulk can return { error } instead of rejecting. Check that field and also handle promise rejections; gRPC RPC failures reject. See state client usage for the complete method and response reference.
Query State API
The alpha query API supports filtering, sorting, and pagination on query-capable stores over HTTP and gRPC. Follow How to: Query state for query expressions, continuation tokens, and result decoding.
PubSub API
For JavaScript SDK 3.19.0 or later, see the publish and subscribe overview to choose a delivery mode.
Publish messages
import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient({ daprHost, daprPort });
try {
const response = await client.pubsub.publish("pubsub", "orders", { orderId: "101" });
if (response.error) {
throw response.error;
}
} finally {
await client.stop();
}
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
See publishing events for bulk operations, metadata, CloudEvents, raw payloads, and transport-specific error handling. See configuration and usage for client lifetime and serialization.
Streaming message subscriptions
With a gRPC client, client.pubsub.subscribeStream() receives messages without DaprServer or an application callback port. Follow the streaming subscription guide for a complete worker, runtime requirements, acknowledgements, cancellation, and failure supervision.
Bindings API
Invoke Output Binding
Output Bindings
import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient({ daprHost, daprPort });
const bindingName = "my-binding-name";
const bindingOperation = "create";
const message = { hello: "world" };
const response = await client.binding.send(bindingName, bindingOperation, message);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
For a full guide on output bindings visit How-To: Use bindings.
Secret API
Retrieve secrets
import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient({ daprHost, daprPort });
const secretStoreName = "my-secret-store";
const secretKey = "secret-key";
// Retrieve a single secret; the result is the secret's key-value data
const secret = await client.secret.get(secretStoreName, secretKey);
// Retrieve all accessible secrets, nested by secret name
const secrets = await client.secret.getBulk(secretStoreName);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
For JavaScript SDK 3.19.0 or later, follow the Secrets how-to guide for a runnable example, or read the Secrets client usage guidance for configuration, TypeScript response validation, and error handling.
In 3.19.0, HTTP get accepts metadata as a query-string string and preserves all values in a multi-valued secret. gRPC get ignores metadata and returns only the first key-value pair. Bulk retrieval preserves nested values with either protocol, but neither exposes bulk metadata.
For the underlying building block, see How to: Retrieve a secret.
Configuration API
Use client.configuration to read application settings and subscribe to changes. The JavaScript SDK requires gRPC for every configuration method; the HTTP client is not supported.
The configuration how-to guide provides runnable examples for @dapr/dapr 3.19.0 or later. The client usage guidance covers all methods, metadata, response shapes, and subscription error limitations.
Get Configuration Keys
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
async function start() {
const client = new DaprClient({
daprHost,
daprPort: process.env.DAPR_GRPC_PORT ?? "50001",
communicationProtocol: CommunicationProtocolEnum.GRPC,
});
try {
const config = await client.configuration.get("config-store", ["key1", "key2"]);
console.log(config);
} finally {
await client.stop();
}
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
Sample output:
{
items: {
key1: { key: 'key1', value: 'foo', version: '', metadata: {} },
key2: { key: 'key2', value: 'bar2', version: '', metadata: {} }
}
}
Subscribe to Configuration Updates
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
async function start() {
const client = new DaprClient({
daprHost,
daprPort: process.env.DAPR_GRPC_PORT ?? "50001",
communicationProtocol: CommunicationProtocolEnum.GRPC,
});
try {
const stream = await client.configuration.subscribeWithKeys("config-store", ["key1", "key2"], async (data) => {
console.log("Subscribe received updates from config store: ", data);
});
try {
await new Promise((resolve) => setTimeout(resolve, 60000));
} finally {
await stream.stop();
}
} finally {
await client.stop();
}
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
Sample output:
Subscribe received updates from config store: {
items: { key2: { key: 'key2', value: 'bar', version: '', metadata: {} } }
}
Subscribe received updates from config store: {
items: { key1: { key: 'key1', value: 'foobar', version: '', metadata: {} } }
}
To watch all keys, use subscribe(storeName, callback). To include store-specific metadata, use subscribeWithMetadata(storeName, keys, metadata, callback). All-key behavior depends on the component. See subscription lifetime and callbacks before relying on a subscription for configuration freshness.
Cryptography API
In @dapr/dapr 3.19.0 or later, client.crypto supports encryption and decryption over both HTTP and gRPC. Pass data and options to receive a Buffer, or pass only options to receive a Node.js Duplex stream.
Prefer gRPC for large payloads and production streaming. Dapr buffers HTTP cryptography output until the request is fully consumed.
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";
async function start() {
const client = new DaprClient({
daprHost: "127.0.0.1",
daprPort: "50001",
communicationProtocol: CommunicationProtocolEnum.GRPC,
});
try {
const ciphertext = await client.crypto.encrypt("A message to encrypt", {
componentName: "crypto-local",
keyName: "symmetric256",
keyWrapAlgorithm: "A256KW",
});
const plaintext = await client.crypto.decrypt(ciphertext, {
componentName: "crypto-local",
});
console.log("Decrypted bytes:", plaintext.length);
} finally {
await client.stop();
}
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
This example requires a configured crypto-local component and a compatible symmetric256 key. Follow the JavaScript Cryptography how-to guide for complete setup and file-stream examples. See the client usage guidance for ciphers, key references, errors, and runtime limitations.
Distributed Lock API
Try Lock and Unlock APIs
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr";
import { LockStatus } from "@dapr/dapr/types/lock/UnlockResponse";
const daprHost = "127.0.0.1";
const daprPortDefault = "3500";
async function start() {
const client = new DaprClient({ daprHost, daprPort });
const storeName = "redislock";
const resourceId = "resourceId";
const lockOwner = "owner1";
let expiryInSeconds = 1000;
console.log(`Acquiring lock on ${storeName}, ${resourceId} as owner: ${lockOwner}`);
const lockResponse = await client.lock.lock(storeName, resourceId, lockOwner, expiryInSeconds);
console.log(lockResponse);
console.log(`Unlocking on ${storeName}, ${resourceId} as owner: ${lockOwner}`);
const unlockResponse = await client.lock.unlock(storeName, resourceId, lockOwner);
console.log("Unlock API response: " + getResponseStatus(unlockResponse.status));
}
function getResponseStatus(status: LockStatus) {
switch (status) {
case LockStatus.Success:
return "Success";
case LockStatus.LockDoesNotExist:
return "LockDoesNotExist";
case LockStatus.LockBelongsToOthers:
return "LockBelongsToOthers";
default:
return "InternalError";
}
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
For a full guide on distributed locks visit How-To: Use Distributed Locks.
Workflow API
DaprClient.workflow exposes the basic workflow management API over HTTP or gRPC. For
@dapr/dapr 3.19.0 or later, use scheduleNewWorkflow, getWorkflowState, and raiseEvent;
the older start, get, and raise names are deprecated aliases.
For authoring workers, durable waits, listing, history retrieval, reruns, and binary-store payload references,
use the separate workflow SDK guides. DaprWorkflowClient uses
gRPC and returns WorkflowState, not the basic API’s response object shown below.
Workflow management
import { DaprClient } from "@dapr/dapr";
async function start() {
const client = new DaprClient();
// Start a new workflow instance
const instanceId = await client.workflow.scheduleNewWorkflow("OrderProcessingWorkflow", {
Name: "Paperclips",
TotalCost: 99.95,
Quantity: 4,
});
console.log(`Started workflow instance ${instanceId}`);
// Get a workflow instance
const workflow = await client.workflow.getWorkflowState(instanceId);
console.log(
`Workflow ${workflow.workflowName}, created at ${workflow.createdAt.toUTCString()}, has status ${
workflow.runtimeStatus
}`,
);
console.log(`Additional properties: ${JSON.stringify(workflow.properties)}`);
// Pause a workflow instance
await client.workflow.pause(instanceId);
console.log(`Paused workflow instance ${instanceId}`);
// Resume a workflow instance
await client.workflow.resume(instanceId);
console.log(`Resumed workflow instance ${instanceId}`);
// Terminate a workflow instance
await client.workflow.terminate(instanceId);
console.log(`Terminated workflow instance ${instanceId}`);
// Purge a workflow instance
await client.workflow.purge(instanceId);
console.log(`Purged workflow instance ${instanceId}`);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});