When designing public APIs for middleware, helpers, and client functions, favor extensible, composable configuration over ad-hoc parameters that are hard to grow later:
verify(token, key, alg, issuer), grow toward verify(token, key, { alg, issuer, audience }) with an overload that still accepts the old alg string.contentTypesAsBinary: (contentType) => boolean or timeout(duration, (c) => new HTTPException(...)). Callbacks give consumers full flexibility without the library needing to anticipate every case.Context (or Request/Response, as appropriate) into these callbacks so consumers can access route params, env bindings, and app state instead of being limited to primitive inputs, e.g. onError: (remote, c) => ..., generator: (c) => string, generateParams: (c) => SSGParams.onAuthSuccess: (c, username) => c.set('user', username) already covers a use case, don’t also add a dedicated usernameContextKey option — extra options multiply the surface area and maintenance cost without adding real capability.vary?: string | string[]) rather than forcing consumers to always wrap a single value.Applying these principles keeps Hono’s own APIs small, predictable, and future-proof: new capabilities can be layered in via callbacks and options objects without breaking changes, and redundant one-off knobs are avoided in favor of a few well-designed extension points.