Pikku - Write Once, Run Everywhere | Pikku

4 min read Original article ↗

One Function. Every Protocol. Zero Duplication.

Write your logic once. Wire it to HTTP, WebSockets, queues, scheduled tasks, CLI, or AI tools (via Model Context Protocol). Same logic. Different protocols.

1. Define Your Function

src/functions/cards.function.ts

export const getCard = pikkuFunc<
{ cardId: string },
{ id: string; title: string; status: string }
>({
func: async ({ database, channel }, { cardId }) => {
const card = await database.query('cards', {
where: { id: cardId }
})

// Works with WebSocket channels and SSE too!
if (channel) {
await channel.send({ type: 'card-fetched', card })
}

return card
},
permissions: { owner: requireOwner },
docs: {
summary: 'Fetch a card by ID',
tags: ['cards']
}
})

2. Wire to Any Protocol

wireHTTP({
method: 'get',
route: '/cards/:cardId',
func: getCard
})

3. Deploy Anywhere

✓ Same authentication, permissions, and validation across all protocols

Long-Running Workflows with Built-in Resilience

Coming in 0.11

Build complex, multi-step processes that survive failures, handle time delays, and maintain state across server restarts.

User Onboarding Workflow

export const onboardingWorkflow = pikkuWorkflowFunc(
async ({ workflow }, { email, userId }) => {
// Step 1: Create user profile (RPC step)
const user = await workflow.do(
'Create user profile',
'createUserProfile',
{ email, userId }
)

// Step 2: Add to CRM (inline step)
const crmUser = await workflow.do(
'Create user in CRM',
async () => crmApi.createUser(user)
)

// Step 3: Wait 5 minutes
await workflow.sleep(
'Wait before welcome email',
'5min'
)

// Step 4: Send welcome email (RPC step)
await workflow.do(
'Send welcome email',
'sendEmail',
{ to: email, template: 'welcome' }
)

return { success: true }
}
)

1. Deterministic Replay

Completed steps are cached and never re-executed. Workflows resume from where they left off after failures or delays.

2. Persistent State

Store state in any database—PostgreSQL and Redis support out of the box. Survives server restarts and you don't pay for the time it isn't running.

3. Time-Based Steps

Sleep steps for delays, reminders, trial expirations, and scheduled follow-ups.

4. RPC & Inline Steps

Mix RPC calls (via queue workers) with inline code. Full type safety across all steps.

Perfect for user onboarding, order fulfillment, payment processing, approval workflows, and any multi-step business process.

What Developers Say

Real feedback from teams using Pikku in production

"So many places in my code base have like three entry points: CLI, public (sometimes protected) HTTP API and internally from within the API. Would be so nice having everything just an invoke away. With Nest it's a pain because you basically have to start the whole API up just to run CLI command."

Alex Harley

Co-founder @ Superbridge

"Ever been annoyed at having to write your code different in a Lambda than in an express handler? Pikku fixes that."

Christoph Sitter

CTO @ spot

Ship Faster, Maintain Less

Write your business logic once and deliver features across all protocols instantly. One source of truth means fewer bugs, faster iterations, and the flexibility to pivot without rewrites.

Tiny runtime with minimal overhead. Bundles as small as 50KB for single-function deployments.

🔗

Type-Safe Clients

Auto-generated from your function definitions

HTTP fetch, WebSocket, and RPC clients with full IntelliSense

🔐

Auth & Permissions

Built-in filters, no manual checks

Cookie, bearer, API key auth with fine-grained permissions

⚙️

Services

Singleton and per-request injection

Database, logger, config—all type-safe and testable

🪆

Middleware

Before/after hooks across all protocols

Logging, metrics, tracing—work everywhere

Schema Validation

Auto-validate against TypeScript input schemas

Runtime validation catches errors before they hit your functions

🪶

Zero Lock-In

Standard TypeScript, no magic

Tiny runtime, bring your own database/logger/tools

Bundle Only What You Deploy

Run your codebase as a monolith, as microservices, or as functions. Pikku creates the smallest bundle for your use case.

🏢

Monolith

Run everything in one process

pikku

~2.8MB

All functions, all protocols

📦

Microservices

Split by domain or feature

pikku --http-routes=/admin

pikku --tags=admin

~180KB

Only admin routes + dependencies

λ

Functions

One function per deployment

pikku --http-routes=/users/:id --types=http

~50KB

Single endpoint + minimal runtime

Get Started in Minutes

Create your first Pikku app with one command. You'll have a function running across HTTP, WebSockets, and more in under 5 minutes.

npm create pikku@latest

Code Examples

Explore live Pikku examples. Functions stay the same - just the deployment changes.

Deploy to:

Fastify

Next.js

AWS Lambda

Cloudflare

Why I Built Pikku

Three core principles that drove Pikku's creation

Watch the Talks

— Yasser Fadl, Creator of Pikku

Ready to Simplify Your Backend?

Stop duplicating logic. Write once, deploy anywhere with Pikku.