Temporal Has a Free Durable Workflow Engine That Never Loses Your State
Source: Dev.to
Introduction
What happens when your payment processing crashes mid‑transaction?
With regular code — data loss.
With Temporal — it resumes exactly where it left off. Temporal makes your workflows durable, reliable, and resumable by default.
Core Benefits
- Durable execution – workflows survive crashes, restarts, and deployments.
- Automatic retries – configurable retry policies per activity.
- Long‑running workflows – run for days, weeks, or months.
- Timers – sleep for hours/days without holding resources.
- Versioning – update workflow code without breaking running instances.
- Visibility – web UI showing all workflow states.
- TypeScript SDK – fully typed, great developer experience.
- Self‑hosted – Docker Compose or Kubernetes.
Getting Started
Run Temporal server
docker compose up -dCreate a project
npx @temporalio/create@latest my-app
cd my-app
npm run startWorkflow Example (workflows.ts)
import { proxyActivities, sleep } from '@temporalio/workflow';
import type * as activities from './activities';
const { sendEmail, chargePayment, provisionAccount } = proxyActivities({
startToCloseTimeout: '30 seconds',
retry: { maximumAttempts: 3 }
});
export async function onboardUser(email: string, plan: string): Promise {
// Step 1: Send welcome email
await sendEmail(email, 'Welcome!');
// Step 2: Charge payment
const paymentId = await chargePayment(email, plan);
// Step 3: Provision account
await provisionAccount(email, plan);
// Step 4: Wait 3 days, then send tips
await sleep('3 days'); // Durable! Survives server restarts.
await sendEmail(email, 'Here are some tips...');
// Step 5: Wait 7 days, check engagement
await sleep('7 days');
await sendEmail(email, "How's it going?");
}If the server crashes after Step 2, Temporal resumes at Step 3 — not from the beginning.
Activities (activities.ts)
export async function sendEmail(to: string, subject: string): Promise {
await resend.emails.send({ to, subject, from: 'app@company.com' });
}
export async function chargePayment(email: string, plan: string): Promise {
const session = await stripe.checkout.sessions.create({
customer_email: email,
line_items: [{ price: plans[plan], quantity: 1 }]
});
return session.id;
}
export async function provisionAccount(email: string, plan: string): Promise {
await db.accounts.create({ data: { email, plan, status: 'active' } });
}Starting a Workflow (client.ts)
import { Client } from '@temporalio/client';
const client = new Client();
const handle = await client.workflow.start('onboardUser', {
taskQueue: 'main',
workflowId: `onboard-${userId}`,
args: ['user@example.com', 'pro']
});
// Check status
const result = await handle.result();Typical Use Cases
- Payment processing – charge, fulfill, refund with guaranteed completion.
- User onboarding – multi‑day sequences that never lose state.
- Data pipelines – ETL jobs that resume from the point of failure.
- Order fulfillment – payment → inventory → shipping → notification.
- Subscription management – billing cycles, upgrades, cancellations.
Feature Comparison
| Feature | Temporal | BullMQ | Inngest | Trigger.dev |
|---|---|---|---|---|
| Durable execution | ✅ Core feature | ❌ | ✅ | ✅ |
| Long‑running | Days/months | Hours | Limited | Hours |
| Workflow state | Automatic | Manual | Automatic | Manual |
| Versioning | Built‑in | None | None | None |
| Visibility UI | Full | Bull Board | Dashboard | Dashboard |
| Self‑hosted | ✅ | ✅ (Redis) | ❌ | ❌ |
| Complexity | Medium | Low | Low | Low |
Conclusion
Temporal is ideal for workflows that must complete—payment processing, order fulfillment, data pipelines, and more. When crashes or restarts could cause state loss, Temporal guarantees durability and reliability, providing enterprise‑grade resilience for any application.