Install and Configure the Kestra JavaScript SDK
For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append.mdto anykestra.io/docs/*URL for plain Markdown.
Use the Kestra JavaScript SDK to interact with the Kestra API from Node.js applications.
Install the JavaScript SDK
Store credentials in environment variables:
KESTRA_BASE_URL=http://localhost:8080KESTRA_USERNAME=root@root.comKESTRA_PASSWORD=Root!1234Install the SDK:
npm install @kestra-io/kestra-sdkConfigure the client
Call configureClient once at application startup, then call setSelectedTenant to set the active tenant. Both are applied globally — you do not need to pass connection details or tenant to individual method calls.
import { configureClient } from "@kestra-io/kestra-sdk";import { setSelectedTenant } from "@kestra-io/kestra-sdk/shared";
configureClient({ baseURL: process.env.KESTRA_BASE_URL ?? "http://localhost:8080", auth: () => `${process.env.KESTRA_USERNAME}:${process.env.KESTRA_PASSWORD}`,});
setSelectedTenant("main");For bearer token authentication, set auth: () => process.env.KESTRA_TOKEN and pass the token directly.
Each API group is a separate subpath module. Import only what you need:
import * as Flows from "@kestra-io/kestra-sdk/flows";import * as Executions from "@kestra-io/kestra-sdk/executions";import * as Kv from "@kestra-io/kestra-sdk/kv";import * as Triggers from "@kestra-io/kestra-sdk/triggers";Create a flow
Send the flow definition as a YAML string:
import * as Flows from "@kestra-io/kestra-sdk/flows";
async function createFlow() { const body = `id: my_flownamespace: my_namespacetasks: - id: hello type: io.kestra.plugin.core.log.Log message: Hello World!`;
const created = await Flows.createFlow({ body }); console.log("Flow created:", created.id);}body must be valid flow YAML. If a flow with the same id and namespace already exists, use updateFlow instead.
Delete a flow
Remove a flow by its namespace and id:
import * as Flows from "@kestra-io/kestra-sdk/flows";
async function deleteFlow() { await Flows.deleteFlow({ namespace: "my_namespace", id: "my_flow" }); console.log("Flow deleted");}Deleting a flow removes its definition. Execution history is retained unless you delete executions separately.
Execute a flow
Trigger an execution and optionally wait for it to complete:
import * as Executions from "@kestra-io/kestra-sdk/executions";
async function executeFlow() { const exec = await Executions.createExecution({ namespace: "my_namespace", id: "my_flow", wait: true, // set false for a non-blocking call }); console.log("Execution started:", exec.id);}Delete an execution
Delete an execution and optionally purge its logs, metrics, and storage:
import * as Executions from "@kestra-io/kestra-sdk/executions";
async function deleteExecution() { await Executions.deleteExecution({ executionId: "your-execution-id", deleteLogs: true, deleteMetrics: true, deleteStorage: true, }); console.log("Execution deleted");}Follow an execution
Stream live execution state updates. followExecution returns a { stream } object where stream is an async iterable of execution events:
import * as Executions from "@kestra-io/kestra-sdk/executions";
async function followExecution() { const { stream } = await Executions.followExecution({ executionId: "your-execution-id", });
for await (const evt of stream) { if (!evt.state) continue; // skip keepalive frames console.log(`Status: ${evt.state.current}`); if (evt.state.current === "SUCCESS" || evt.state.current === "FAILED") break; }}The server emits an initial keepalive event with no state — skip it before processing updates.
KV Store
The KV Store lets you read and write key-value pairs scoped to a namespace.
Set a value
import * as Kv from "@kestra-io/kestra-sdk/kv";
async function setKvValue() { await Kv.setKeyValue({ namespace: "my_namespace", key: "my_key", body: "my_value" }); console.log("Key set");}Get a value
import * as Kv from "@kestra-io/kestra-sdk/kv";
async function getKvValue() { const result = await Kv.keyValue({ namespace: "my_namespace", key: "my_key" }); console.log("Value:", result?.value);}Delete a key
import * as Kv from "@kestra-io/kestra-sdk/kv";
async function deleteKvKey() { await Kv.deleteKeyValue({ namespace: "my_namespace", key: "my_key" }); console.log("Key deleted");}Manage triggers
Search triggers
import * as Triggers from "@kestra-io/kestra-sdk/triggers";
async function searchTriggers() { const result = await Triggers.searchTriggers({ page: 1, size: 50 }); result.results?.forEach(t => { console.log(`${t.triggerContext?.triggerId}: disabled=${t.triggerContext?.disabled}`); });}Disable or enable a trigger
import * as Triggers from "@kestra-io/kestra-sdk/triggers";
async function disableTrigger() { await Triggers.disabledTriggersByIds({ triggers: [{ namespace: "my_namespace", flowId: "my_flow", triggerId: "my_schedule" }], disabled: true, // pass false to re-enable }); console.log("Trigger disabled");}Restart a trigger
import * as Triggers from "@kestra-io/kestra-sdk/triggers";
async function restartTrigger() { await Triggers.restartTrigger({ namespace: "my_namespace", flowId: "my_flow", triggerId: "my_schedule", }); console.log("Trigger restarted");}Unlock a trigger
import * as Triggers from "@kestra-io/kestra-sdk/triggers";
async function unlockTrigger() { await Triggers.unlockTrigger({ namespace: "my_namespace", flowId: "my_flow", triggerId: "my_schedule", }); console.log("Trigger unlocked");}Best practices
- Configure once: call
configureClientandsetSelectedTenantonce at startup and reuse them globally. - Externalize config: keep URL and auth in environment variables.
- Validate YAML: invalid flow YAML returns
422responses. - Use labels for governance, search, and routing across executions.
Was this page helpful?