Hyperjump Web Framework (WIP)Hyperjump Web Framework (WIP)
Route Action Gen

Generated Files

When you run npx route-action-gen, the CLI generates files in a .generated/ directory and creates an entry point file in the config directory if one does not exist.

  • App Router: generated files are placed in .generated/ inside the config directory (e.g. app/api/posts/.generated/).
  • Pages Router: generated files are placed at the project root under .generated/ in a mirror of the config path (e.g. .generated/pages/api/users/). This prevents Next.js from treating them as API routes.

The set of generated files depends on the framework and the HTTP methods defined.

App Router

For the Next.js App Router, the entry point file is route.ts:

app/api/posts/[postId]/route.ts
export * from "./.generated/route";

Files generated for all methods

These files are always generated regardless of the HTTP method:

FileDescription
route.tsThe Next.js route handler. Exports named functions (GET, POST, etc.) for each method defined in the config files.
client.tsA RouteClient class with typed methods for each HTTP method. Use this from non-React apps or scripts.
use-route-[method].tsxA React hook for each HTTP method (e.g. use-route-get.tsx, use-route-post.tsx). Provides data, error, isLoading, and fetchData.
README.mdDocumentation for the generated files.

Files generated for body methods only

For methods that accept a request body (POST, PUT, PATCH), additional files are generated:

FileDescription
server.function.tsA "use server" server function that wraps the handler. Can be called directly from server components.
form.action.tsA form action wrapper that parses FormData and calls the handler. Works with React's <form action={...}>.
use-server-function.tsxA React hook that calls the server function using useTransition.
use-form-action.tsxA React hook that calls the form action using useActionState.
form-components.tsxAuto-generated form input and label components based on the Zod schemas for body and param fields. Only generated when the config has body or param fields.

Example directory structure

Given route.get.config.ts and route.post.config.ts in the same directory:

route.get.config.ts
route.post.config.ts
route.ts
route.ts
client.ts
use-route-get.tsx
use-route-post.tsx
server.function.ts
form.action.ts
use-server-function.tsx
use-form-action.tsx
form-components.tsx
README.md

Pages Router

For the Next.js Pages Router, the entry point file is index.ts. The import path points to the project-root .generated/ mirror:

pages/api/users/index.ts
export { default } from "../../../.generated/pages/api/users/route";

The Pages Router uses a single default export via createPagesRoute instead of multiple named exports.

Files generated for all methods

FileDescription
route.tsThe API route handler. Uses createPagesRoute to produce a single default export that handles all configured methods.
client.tsA RouteClient class, same as the App Router version.
use-route-[method].tsxA React hook for each HTTP method.
README.mdDocumentation for the generated files.

Files generated for body methods only

FileDescription
form-components.tsxAuto-generated form components. Only generated when the config has body or param fields.

Good to know

The Pages Router does not generate server functions, form actions, or their corresponding hooks (server.function.ts, form.action.ts, use-server-function.tsx, use-form-action.tsx). These are App Router features that rely on React Server Components.

Config file default export

Next.js treats every .ts / .tsx file under pages/api/ as an API route and requires a default export. Since config files (route.*.config.ts) are not actual route handlers, you must add a no-op default export:

export default function _noop() {}

Required

Without this export, the Next.js build will fail with a type error: Property 'default' is missing in type ... but required in type 'ApiRouteConfig'.

Example directory structure

route.get.config.ts
route.post.config.ts
index.ts
route.ts
client.ts
use-route-get.tsx
use-route-post.tsx
form-components.tsx
README.md

Using the generated code

Route handler

The generated route.ts handles request parsing, validation, auth, and error handling. You do not need to edit it. The entry point file re-exports everything from .generated/route.ts.

React hooks

Each use-route-[method].tsx exports a hook (e.g. useRouteGet, useRoutePost) that returns:

PropertyTypeDescription
dataz.infer<typeof responseValidator> | nullThe validated response data, or null before the first call.
errorError | nullAny error that occurred during the request.
isLoadingbooleanWhether the request is in flight.
fetchData(input) => Promise<void>Triggers the request with typed input (body, params, searchParams, headers as needed).
app/posts/page.tsx
"use client";

import { useRouteGet } from "../api/posts/[postId]/.generated/use-route-get";

export default function PostPage() {
  const { data, error, isLoading, fetchData } = useRouteGet();

  return (
    <div>
      {isLoading && <div>Loading...</div>}
      {error && <div>{error.message}</div>}
      {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
      <button onClick={() => fetchData({ params: { postId: "1" } })}>
        Fetch Post
      </button>
    </div>
  );
}

Client class

The RouteClient class is framework-agnostic and works in any JavaScript environment:

import { RouteClient } from "./app/api/posts/[postId]/.generated/client";

const client = new RouteClient({ baseUrl: "http://localhost:3000" });
const result = await client.get({ params: { postId: "1" } });

Server function

The generated server.function.ts exports a function marked with "use server". You can call it directly from a server component or use it via the useServerFunction hook:

import { useServerFunction } from "../api/posts/[postId]/.generated/use-server-function";

const { data, error, isPending, execute } = useServerFunction();

Form action

The generated form.action.ts works with React's form action pattern. Use it with the useFormAction hook:

import { useFormAction } from "../api/posts/[postId]/.generated/use-form-action";

const { state, formAction, isPending } = useFormAction();

Or use the auto-generated form components:

import { PostForm } from "../api/posts/[postId]/.generated/form-components";

Ignoring generated files

The .generated/ directories should not be committed to version control. Add the following to your .gitignore:

.generated/

All generated files include a header comment indicating they are auto-generated:

/** THIS FILE IS AUTOMATICALLY GENERATED BY ROUTE-ACTION-GEN **/
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck