import { pageMetadata } from "@/lib/page-metadata"
export const metadata = pageMetadata("docs/api/next")
# @json-render/next
Next.js renderer. JSON becomes full Next.js applications with routes, layouts, metadata, and SSR.
## Installation
```bash
npm install @json-render/core @json-render/react @json-render/next
```
## schema
The Next.js app schema for multi-page specs. Use with `defineCatalog` from core.
```typescript
import { defineCatalog } from '@json-render/core';
import { schema } from '@json-render/next/server';
import { z } from 'zod';
const catalog = defineCatalog(schema, {
components: {
Card: {
props: z.object({ title: z.string() }),
description: 'Card container',
},
NavBar: {
props: z.object({ links: z.array(z.object({ href: z.string(), label: z.string() })) }),
description: 'Navigation bar',
},
},
actions: {},
});
```
## createNextApp
Create all exports needed for a Next.js `[[...slug]]` catch-all route.
```typescript
import { createNextApp } from '@json-render/next/server';
const { Page, generateMetadata, generateStaticParams } = createNextApp({
spec: myAppSpec,
loaders: {
loadPost: async ({ slug }) => {
const post = await db.post.findUnique({ where: { slug } });
return { post };
},
},
});
```
### Options
| Option |
Type |
Description |
spec |
{'NextAppSpec | (() => NextAppSpec | Promise)'} |
The application spec (static or dynamic) |
loaders |
{'Record'} |
Server-side data loaders keyed by name |
### Returns
| Export |
Description |
Page |
Async Server Component for page.tsx |
generateMetadata |
Metadata generator for Next.js SEO |
generateStaticParams |
Static params for pre-rendering at build time |
## NextAppSpec
The top-level spec defining an entire Next.js application.
```typescript
interface NextAppSpec {
metadata?: NextMetadata;
routes: Record;
layouts?: Record;
state?: Record;
}
```
### Route Patterns
Routes use Next.js URL conventions:
| Pattern |
Example Match |
Params |
/ |
/ |
{'{}'} |
/about |
/about |
{'{}'} |
/blog/[slug] |
/blog/hello |
{'{ slug: "hello" }'} |
/docs/[...path] |
/docs/a/b/c |
{'{ path: ["a","b","c"] }'} |
/app/[[...path]] |
/app or /app/x/y |
{'{ path: [] }'} or {'{ path: ["x","y"] }'} |
## NextAppProvider
Client component that provides the component registry and action handlers to all pages.
```tsx
import { NextAppProvider } from '@json-render/next';
export default function Layout({ children }) {
return (
{children}
);
}
```
## Built-in Components
### Slot
Placeholder in layouts where page content is rendered. Every layout MUST include a Slot.
```json
{ "type": "Slot", "props": {}, "children": [] }
```
### Link
Client-side navigation wrapping `next/link`.
```json
{ "type": "Link", "props": { "href": "/about" }, "children": ["link-text"] }
```
## Built-in Actions
| Action |
Params |
Description |
setState |
{'{ statePath, value }'} |
Update a value in state |
pushState |
{'{ statePath, value, clearStatePath? }'} |
Append to array in state |
removeState |
{'{ statePath, index }'} |
Remove from array by index |
navigate |
{'{ href }'} |
Client-side navigation |
## Server Utilities
### matchRoute
Match a pathname against a spec's routes.
```typescript
import { matchRoute } from '@json-render/next/server';
const matched = matchRoute(spec, '/blog/hello-world');
// { route: NextRouteSpec, pattern: '/blog/[slug]', params: { slug: 'hello-world' } }
```
### resolveMetadata
Resolve merged metadata for a route.
```typescript
import { resolveMetadata } from '@json-render/next/server';
const metadata = resolveMetadata(spec, matchedRoute?.route);
```
### slugToPath
Convert catch-all slug array to pathname.
```typescript
import { slugToPath } from '@json-render/next/server';
slugToPath(undefined); // "/"
slugToPath(['blog', 'hello']); // "/blog/hello"
```
## Entry Points
| Import |
Contents |
@json-render/next |
Client components (NextAppProvider, PageRenderer, Link) |
@json-render/next/server |
Server utilities (createNextApp, matchRoute, schema) |