You need to onboard a user: create their profile, wait 5 minutes, send a welcome email, provision their workspace. If the email service is down, the whole thing fails. You end up building retry logic, state machines, and dead-letter queues. For what should be 10 lines of code.
Sequential code. Durable execution.
Write it like normal async code. Pikku handles persistence, retries, and resumption.
You write this
export const onboardUser = pikkuWorkflow({
input: z.object({
email: z.string(),
userId: z.string(),
}),
func: async ({ workflow, rpc }, data) => {
// Step 1 — persisted, retried on failure
await workflow.do('Create profile', 'createProfile', data)
// Step 2 — sleeps for real (minutes, hours, days)
await workflow.sleep('Wait before welcome', '5m')
// Step 3 — resumes here if the server restarted
await workflow.do('Send welcome email', 'sendEmail', {
to: data.email,
template: 'welcome',
})
// Step 4
await workflow.do('Provision workspace', 'createWorkspace', {
userId: data.userId,
})
return { success: true }
},
})
Pikku handles
Each step is persisted
State saved to PostgreSQL or Redis after every step. Nothing lost.
Automatic retries
If sendEmail fails, Pikku retries that step. Previous steps are not re-run.
Real sleep
workflow.sleep pauses for real time — 5 minutes, 2 hours, 7 days. Server can restart.
Deterministic replay
On restart, Pikku replays from the exact step that failed. No duplicate side effects.
Full observability
Every step is traced. See which step is running, which completed, which failed.
Same auth model
Workflows use the same permissions as your functions. No separate auth layer.
Trigger from anywhere. Watch it run.
Workflows are functions. Wire them to any surface.
// Via HTTP
wireHTTP({ method: 'post', route: '/onboard', func: onboardUser })
// Via queue (on user signup event)
wireQueueWorker({ queue: 'signups', func: onboardUser })
// Via cron (batch onboarding)
wireScheduler({ schedule: '0 9 * * *', func: batchOnboard })
// Via AI agent
pikkuAIAgent({
name: 'ops-assistant',
tools: [onboardUser],
model: 'anthropic/claude-sonnet-4-5',
})
No YAML. No state machines. No separate engine.
Temporal requires a separate server and custom workers. Inngest needs event schemas and a webhook endpoint. Step Functions need JSON definitions and an AWS account. Pikku workflows are TypeScript functions — same as everything else in your codebase.
Temporal
Separate server + workers
Inngest
Event schemas + webhooks
Step Functions
JSON + AWS lock-in
Pikku: just a function. Same auth, same types, same deploy.
Ship your first workflow in 5 minutes.
Write a workflow. Deploy to Fabric. Watch it run with full traces.