Skip to main content
Core Concept

Your toolbox.
Injected.

Two factory functions — pikkuServices and pikkuWireServices — wire your entire application together with full type safety and tree-shaking.

The Two Factories

Two functions. Everything wired.

pikkuServices creates singletons at startup. pikkuWireServices creates per-request services. That's the whole model.

pikkuServices — Singletons

Created once at startup, shared across all requests. Database pools, loggers, JWT, third-party clients. Receives (config, existingServices).

pikkuWireServices — Per-request

Created fresh per HTTP request, queue job, CLI command, or WebSocket lifetime. Sessions, transactions, audit contexts. Receives (singletonServices, wire).

Destructure what you need

Functions declare dependencies explicitly. Pikku merges singleton + wire services so your function sees one flat object. Only pull what you use.

services.tsstartup
import { pikkuServices } from '#pikku'

export const createSingletonServices = pikkuServices(
async (config, existingServices) => {
const logger = new ConsoleLogger()
const database = new DatabasePool(config.database)
await database.connect()

const jwt = new JoseJWTService(
async () => [{ id: 'my-key', value: JWT_SECRET }],
logger
)

return {
config,
logger,
database,
jwt,
books: new BookService(),
}
}
)
services.tsper-request
import { pikkuWireServices } from '#pikku'

export const createWireServices = pikkuWireServices(
async (singletonServices, wire) => {
// Created fresh per request / queue job / CLI command
// Pikku merges these with singleton services automatically
return {
userSession: createUserSessionService(wire),
dbTransaction: new DatabaseTransaction(
singletonServices.database
),
}
}
)

Tree-Shaking

Only load what you actually use.

Pikku's CLI generates requiredSingletonServices — a map of which services your filtered functions need. Pair it with dynamic import() calls to skip everything else.

CLI scans destructuring

Pikku analyzes which services each function, middleware, and permission actually destructures from the services parameter.

Generates requiredSingletonServices

A boolean map marking each service true or false. Plus a RequiredSingletonServices type that narrows your factory's return type.

Dynamic imports skip unused services

Guard heavy imports with if (requiredSingletonServices.x). When a service isn't needed, the import is never executed — zero cold-start overhead.

.pikku/pikku-services.gen.tsauto-generated
// .pikku/pikku-services.gen.ts  (auto-generated)
export const requiredSingletonServices = {
'database': true, // used by getUser, deleteUser
'audit': true, // used by deleteUser
'cache': false, // not used by any wired function
'jwt': true, // used by auth middleware
} as const

export type RequiredSingletonServices =
Pick<SingletonServices, 'database' | 'audit' | 'jwt'>
& Partial<Omit<SingletonServices, 'database' | 'audit' | 'jwt'>>
services.tsyour code
import { requiredSingletonServices } from '.pikku/pikku-services.gen.js'
import { pikkuServices } from '#pikku'

export const createSingletonServices = pikkuServices(
async (config) => {
const logger = new ConsoleLogger()

// Only create JWT if wired functions actually need it
let jwt: JWTService | undefined
if (requiredSingletonServices.jwt) {
const { JoseJWTService } = await import('@pikku/jose')
jwt = new JoseJWTService(keys, logger)
}

// Only connect to database if needed
let database: Database | undefined
if (requiredSingletonServices.database) {
database = await createDatabase(config.databaseUrl)
}

return { config, logger, jwt, database }
}
)

Faster cold starts

Health-check endpoints don't load your database driver. Payment endpoints don't load your email SDK.

Same codebase

Deploy as monolith, microservices, or individual functions — filter with CLI flags, no code changes.

Type-safe

RequiredSingletonServices narrows your factory return type so TypeScript catches missing services at compile time.

Start building in 5 minutes

Scaffold a project with services pre-configured. Add your own, destructure what you need, and deploy anywhere.

$ npm create pikku@latest

MIT Licensed  ·  Works with Express, Fastify, Lambda & Cloudflare