Skip to content
Nile Js
Build your application

Hooks and pipelines

Compose shared policies and action-specific work in a defined execution order

Read Markdown ↗

Use hooks for checks or transformations shared by several actions. Global hooks run across the application; local hooks form part of an action’s pipeline.

Know when each step runs

For an executed action, the order is:

  1. Built-in JWT authentication, if both auth and isProtected are configured.
  2. Global onBeforeActionHandler.
  3. Action hooks.before, in their listed order.
  4. The main action's Zod validation.
  5. Main handler.
  6. Action hooks.after, in their listed order, after handler success.
  7. Global onAfterActionHandler, after successful preceding steps.

A before hook sees input before validation. Check the values it uses; do not treat the payload as validated business input yet. A failing step stops later steps except for a noncritical local hook failure.

Global checks

Require a session before a protected action runs:

import type { BeforeActionHandler } from "@nilejs/nile";
import { Err, Ok } from "@nilejs/nile/fp";

const onBeforeActionHandler: BeforeActionHandler<boolean, string> = (
  hookContext
) => {
  const session = hookContext.nileContext.getSession("rest");
  if (hookContext.action.isProtected && session === undefined) {
    return Err("Sign in to continue");
  }
  return Ok(true);
};

Set onBeforeActionHandler in your server configuration to this hook. Global before-hook success allows execution to continue; its returned value does not replace the payload. Use local before hooks for transformations. Global before-hook failure always stops execution.

The global after hook receives { nileContext, action, payload, result }. Its Result becomes the final output; returning an error stops success. It is not an always-run finally callback and does not run after an earlier failure.

Local transformations

Local hooks reference registered actions:

hooks: {
  before: [
    { service: "policies", action: "prepare-project", isCritical: true },
  ],
  after: [
    { service: "presenters", action: "project-summary", isCritical: true },
  ],
}

The before chain starts with the original payload. Each successful hook's value becomes the next hook's input, then the main schema validates the final value. The after chain starts with the handler's successful value and similarly replaces the eventual response.

A referenced hook runs its handler directly. Nile does not recursively run that action's own authentication, validation or hook pipeline. Put required checks inside the hook handler; setting isProtected on a referenced hook alone does not protect the parent operation.

Local hook outcomeisCritical: trueisCritical: false
Ok(value)Pass value to the next stepPass value to the next step
Err(message)Stop with failureRecord failure and keep the preceding value
Missing referenced actionStop with failureRecord the diagnostic and continue

Use noncritical steps only when losing that step is acceptable. They do not roll back earlier writes. For observation that must preserve the result, return the received input on success.

Keep state local to the execution

Hooks and the handler share nileContext.hookContext for the current action execution. updateHookState(key, value) stores execution-local information. Global hooks still run; their state is isolated between concurrent and nested action executions.

result: { pipeline: true } returns { data: finalOutput, pipeline: hookLogs } as the action value. Hook logs include inputs and outputs, so enable this only when those details are suitable for the caller. This is a debugging aid, not a durable audit trail.

On this page