Skip to main content

Hello world in Node

In this tutorial we'll go over the different components that make up a Temporal project. All of the code in this page is included in our package initializer, set it up using the getting started instructions.

The SDK steers developers to write their Workflows and Activities in TypeScript but vanilla JS is also supported. All examples in the documentation are written in TypeScript.


API reference

Activities are called from Workflows in order to run non-deterministic code.

Activities are just async functions, they run like typical NodeJS code and can be cancelled and report heartbeats.


export async function greet(name: string): Promise<string> {
return `Hello, ${name}!`;


API reference

Workflows are the core of the Temporal system, they abstract away the complexities of writing distributed programs.

In the NodeJS SDK, each Workflow runs in a separate V8 isolate to provide a deterministic runtime.


A Workflow's interface is used for validating the implementation and generating a type safe WorkflowClient and ChildWorkflow (not yet implemented).

Workflow interfaces are directly referenced by their implementation and may be written in sync or async form meaning a method could return number or it could return Promise<number>.

Workflow interface declarations are optional, they're only required for generating type safe clients. It is considered good practice to declare an interface for each Workflow.


import { Workflow } from '@temporalio/workflow';
// Extend the generic Workflow interface to check that Example is a valid workflow interface
// Workflow interfaces are useful for generating type safe workflow clients
export interface Example extends Workflow {
main(name: string): Promise<string>;


A Workflow implmentation module may export a workflow object which can be type checked using a pre-defined interface or main - and optionally signals and queries - directly.

In a Workflow, Activities can be imported and called as regular functions. At runtime, the imported Activities (prefixed with @activities) are replaced with stubs which schedule Activities in the system.

@activities is a typescript path alias set to src/activities.


import { Example } from '../interfaces/workflows';
import { greet } from '@activities/greeter';
// A workflow that simply calls an activity
async function main(name: string): Promise<string> {
return greet(name);
// Declare the workflow's type to be checked by the Typescript compiler
export const workflow: Example = { main };


API reference

The Worker connects to the Service and runs Workflows and Activities. Worker.create() accepts these options.


import { Worker } from '@temporalio/worker';
async function run() {
// Automatically locate and register Activities and Workflows relative to __dirname
// (assuming package was bootstrapped with `npm init @temporalio`).
// Worker connects to localhost by default and uses console error for logging.
// Customize the Worker by passing more options to create().
// create() tries to connect to the server and will throw if a connection could not be established.
// You may create multiple Workers in a single process in order to poll on multiple task queues.
// In order to configure the server connection parameters and other global options,
// use the Core.install() method to configure the Rust Core SDK singleton.
const worker = await Worker.create({ workDir: __dirname, taskQueue: 'tutorial' });
// Start accepting tasks on the `tutorial` queue
run().catch((err) => {


API reference

The client can be used to schedule Workflows and send other requests to the Temporal Service. It can be used in any NodeJS process e.g an express app and does not depend on the Worker.


import { Connection } from '@temporalio/client';
import { Example } from '../interfaces/workflows';
async function run() {
// Connect to localhost with default ConnectionOptions,
// pass options to the Connection constructor to configure TLS and other settings.
const connection = new Connection();
// Create a typed client using the Example Workflow interface,
// Workflow will be started in the "default" namespace unless specified otherwise.
const example = connection.workflow<Example>('example', { taskQueue: 'tutorial' });
const result = await example.start('Temporal');
console.log(result); // Hello, Temporal!
run().catch((err) => {


There's no official support for testing Workflows and Activities.

  • Since Activities are async functions they should be testable as long as you avoid using Context or are able to mock it.
  • You can test Workflows by running them with a WorkflowClient.

Get notified of updates