> ## Documentation Index
> Fetch the complete documentation index at: https://eo.utopy.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Middleware

> Use native oRPC middleware, Effect generators, and Effect-returning middleware together.

`.use(...)` accepts native oRPC middleware, generator-based Effect middleware, and Effect-returning middleware.

Use Effect middleware when the middleware needs Effect services, Effect errors, or Effect control flow.

## Gate middleware

A gate runs checks and lets the pipeline continue automatically.

```ts title="gate.ts" theme={null}
const authedProcedure = effectProcedure.use(function* () {
  const user = yield* CurrentUser;
  yield* requireActiveUser(user);
});
```

## Wrap middleware

A wrap calls `next(...)` explicitly and returns its result.

```ts title="wrap.ts" theme={null}
const authedProcedure = effectProcedure.use(function* ({ next }) {
  const user = yield* CurrentUser;
  yield* requireActiveUser(user);

  return yield* next({
    context: { userId: user.id },
  });
});
```

## Effect-returning middleware

Use `Effect.fn(...)` or a function returning `Effect.gen(...)` when you already have an Effect-returning callback shape. Guard-only Effect middleware can return `void`; the pipeline continues automatically.

```ts title="effect-returning.ts" theme={null}
const authedProcedure = effectProcedure.use(
  Effect.fn("middleware.auth")(function* ({ next }) {
    const user = yield* CurrentUser;
    return yield* next({ context: { userId: user.id } });
  }),
);

const auditedProcedure = effectProcedure.use(({ next }) =>
  Effect.gen(function* () {
    yield* Effect.logDebug("before handler");
    return yield* next();
  }),
);
```

## Transform output

```ts title="output-transform.ts" theme={null}
const wrapped = effectProcedure.use(function* ({ next }, _input, output) {
  const result = yield* next();
  return yield* output({
    ...result.output,
    wrapped: true,
  });
});
```

## Reusable Effect middleware

Use `.middleware(...)` to define Effect middleware once and pass it to `.use(...)`.

```ts title="reusable.ts" theme={null}
const requireAdmin = effectProcedure.middleware(function* ({ next }) {
  const user = yield* CurrentUser;
  yield* requireAdminUser(user);
  return yield* next();
});

const adminProcedure = effectProcedure.use(requireAdmin);
```

## Native oRPC middleware still works

```ts title="native.ts" theme={null}
const withRequestLabel = effectProcedure.use(({ context, next }) =>
  next({
    context: {
      requestLabel: `${context.role}:${context.requestId}`,
    },
  }),
);

const checked = effectProcedure.use(({ context }) => {
  if (!context.requestId) throw new Error("missing request id");
  // Returning void is a native guard: the pipeline continues automatically.
});
```

<Note>
  Native middleware can split contiguous Effect runtime boundaries. If you need
  request-local Effect context continuity across those boundaries in Node, see
  [Node context bridge](/effect-v4/guides/node-fiber-context).
</Note>

## Next step

Use contracts with [Contract-first APIs](/effect-v4/capabilities/contract-first).
