Skip to main content
Pikku Fabric use case

Workflows that
survive anything.

Write multi-step processes as sequential code. Pikku persists each step, retries on failure, and resumes exactly where it left off. No external workflow engine.

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.

Trigger a workflow
// 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',
})
workflow trace
onboardUser — completed
✓ Create profile 12ms
◷ Wait before welcome 5m sleep
✓ Send welcome email 340ms
✓ Provision workspace 1.2s
Total: 5m 1.6s — success
Retries: 1 (sendEmail, attempt 2 succeeded)

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.