This repository demonstrates how Temporal can be used for distributed workflow orchestration in a modern TypeScript monorepo. It showcases how Temporal handles complex business processes across multiple services with built-in reliability.
- Temporal - Workflow orchestration ⚡
- TypeScript - Language 💪
- Express - API framework 🌐
- Turborepo - Monorepo tooling 🛠️
The demo implements an investment workflow that spans multiple services:
graph LR
API[REST API] --> T[Temporal Server]
T --> IW[Investment Worker]
IW --> T
T --> EW[Email Worker]
apps/api: REST API that initiates workflowsapps/investment-worker: Handles investment processingapps/email-worker: Manages email notifications- Temporal Server: Orchestrates the entire workflow
- Install dependencies:
pnpm install- Start Temporal Server:
pnpm temporal # or pnpm temporal:start
# To stop the server later:
pnpm temporal:stop- Start all services:
pnpm devThis will start:
- API server at http://localhost:3000
- Investment worker
- Email worker
- Temporal UI at http://localhost:8080
Make an investment request:
# Start an investment workflow
curl -X POST http://localhost:3000/invest \
-H "Content-Type: application/json" \
-d '{
"userId": "user123",
"amount": 1000
}'
# Response:
# {
# "workflowId": "investment-user123-1234567890"
# }The workflow will:
- Record the investment (handled by investment-worker)
- Send a confirmation email (handled by email-worker)
- You can watch the progress in the logs or Temporal UI
Here's a demonstration of Temporal's durability:
- Start a workflow as shown above
- Investment worker logs:
Investment workflow started { userId: 'user123', amount: 1000 }
Investment recorded { userId: 'user123' }
[Process exits unexpectedly]
- The workflow will pause. Start the services again:
pnpm dev- Watch it continue automatically:
Worker connected, waiting for tasks...
Starting email workflow { userId: 'user123' }
Investment workflow completed { userId: 'user123' }
The workflow continues without any data loss or manual intervention! 🎉
apps/
├── api/ # REST API
├── investment-worker # Investment processing service
└── email-worker # Email notification service
infra/
└── temporal/ # Temporal server configuration
When you run the workflow, you'll see the following logs:
Worker connected, waiting for tasks...
2025-08-17T12:20:13.521Z [INFO] Worker state changed {
sdkComponent: 'worker',
taskQueue: 'investment-queue',
state: 'RUNNING'
}
2025-08-17T12:20:31.037Z [INFO] Investment workflow started {
sdkComponent: 'workflow',
taskQueue: 'investment-queue',
namespace: 'default',
workflowId: 'investment-user2-1755433230984',
runId: '0198b7f9-628b-7a13-999c-4bbd8e1b8366',
workflowType: 'investmentWorkflow',
userId: 'user2',
amount: 500
}
Recording investment { userId: 'user2', amount: 500 }
Investment saved to memory { userId: 'user2' }
2025-08-17T12:20:31.069Z [INFO] Investment recorded {
sdkComponent: 'workflow',
taskQueue: 'investment-queue',
namespace: 'default',
workflowId: 'investment-user2-1755433230984',
runId: '0198b7f9-628b-7a13-999c-4bbd8e1b8366',
workflowType: 'investmentWorkflow',
userId: 'user2',
amount: 500
}
2025-08-17T12:20:31.081Z [INFO] Starting email workflow {
sdkComponent: 'workflow',
taskQueue: 'investment-queue',
namespace: 'default',
workflowId: 'investment-user2-1755433230984',
runId: '0198b7f9-628b-7a13-999c-4bbd8e1b8366',
workflowType: 'investmentWorkflow',
userId: 'user2'
}
2025-08-17T12:20:31.096Z [INFO] Investment workflow completed {
sdkComponent: 'workflow',
taskQueue: 'investment-queue',
namespace: 'default',
workflowId: 'investment-user2-1755433230984',
runId: '0198b7f9-628b-7a13-999c-4bbd8e1b8366',
workflowType: 'investmentWorkflow',
userId: 'user2'
}
2025-08-17T12:20:13.521Z [INFO] Worker state changed { sdkComponent: 'worker', taskQueue: 'email-queue', state: 'RUNNING' }
2025-08-17T12:20:31.133Z [INFO] Email workflow started {
sdkComponent: 'workflow',
taskQueue: 'email-queue',
namespace: 'default',
workflowId: 'email-user2-1755433231075',
runId: '0198b7f9-62ed-7d55-8f07-0e34e14dc45a',
workflowType: 'sendEmailWorkflow',
to: 'user2@example.com'
}
=== Simulated Email ===
To: user2@example.com
Subject: Investment Confirmation
Body: Your investment of $500 has been received.
====================
Email sent successfully
2025-08-17T12:20:31.680Z [INFO] Email workflow completed {
sdkComponent: 'workflow',
taskQueue: 'email-queue',
namespace: 'default',
workflowId: 'email-user2-1755433231075',
runId: '0198b7f9-62ed-7d55-8f07-0e34e14dc45a',
workflowType: 'sendEmailWorkflow',
to: 'user2@example.com'
}
These logs show the complete flow:
- Investment worker receives and processes the investment
- Triggers the email workflow
- Email worker receives and processes the email request
- Both workflows complete successfully