Skip to content
Writenex is part of Juhenza Technologies

Visual Editor for
Next.js Content

Visual Markdown and MDX editing, typed frontmatter, image uploads, and version history. All inside your Next.js project.

@imjp/writenex-next · v1.14.0 · Next.js 15 & 16 · App Router · Node.js

Quick Start

Connect the App Router route, then open your editor.

Install the package

terminal
npm install @imjp/writenex-next

Connect your Next.js configuration

next.config.mjs
import { withWritenex } from "@imjp/writenex-next";

export default withWritenex({
  // Keep your existing Next.js options here.
});

Create the editor route

app/%5Fwritenex/[[...path]]/route.ts
import { createWritenexHandler } from "@imjp/writenex-next/server";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

const handler = createWritenexHandler();
export const GET = handler;
export const HEAD = handler;
export const POST = handler;
export const PUT = handler;
export const DELETE = handler;
export const PATCH = handler;
export const OPTIONS = handler;

Use the literal %5Fwritenex folder name: Next.js treats folders starting with an underscore as private. Keep [[...path]] to serve the editor, API, and assets. Projects using src/app should create the route there. Do not add a page.tsx alongside it.

Start editing

terminal
npm run dev
# Open http://localhost:3000/_writenex

The Writenex editing experience

Visual Markdown & MDX

Write with the visual editor or switch to source mode. Content stays in your project as Markdown and MDX files.

Content collections

Discover collections inside content/ and src/content/, or choose explicit paths in writenex.config.ts.

Typed frontmatter

Use the shared Fields API for text, selections, dates, images, structured data, validation, and more.

Image uploads

Upload images alongside content or into your public directory with the same storage strategies as Astro.

Version history

Save automatic snapshots and restore earlier drafts. Version files stay on your project's filesystem.

Your existing site

The editor runs in its own HTML document. Its styles and bundled React stay outside your site's layouts.

Content collections & Fields API

Subdirectories of content/ and src/content/ become collections automatically. Frontmatter forms are inferred from existing files. For explicit fields and preview URLs, add a configuration file:

writenex.config.ts
import { defineConfig, collection, fields } from "@imjp/writenex-next/config";

export default defineConfig({
  collections: [
    collection({
      name: "blog",
      path: "content/blog",
      filePattern: "{slug}.mdx",
      previewUrl: "/blog/{slug}",
      schema: {
        title: fields.text({
          label: "Title",
          validation: { isRequired: true },
        }),
        description: fields.text({ label: "Description", multiline: true }),
        draft: fields.checkbox({ label: "Draft", defaultValue: true }),
        body: fields.mdx({ label: "Content" }),
      },
    }),
  ],
  editor: { autosave: true, autosaveInterval: 3000 },
  images: { strategy: "colocated" },
  versionHistory: { enabled: true, maxVersions: 20 },
});

Configured paths take precedence. Set discovery: { enabled: false } to use only configured collections. The Fields API matches Astro; import defineConfig, collection, singleton, and fields from @imjp/writenex-next/config.

Preview URLs must match your own site routes. Use source mode for custom MDX components or expressions that the visual editor cannot round-trip, and verify the result in your site's preview.

Runtime configuration

Pass these options to createWritenexHandler() in your route file.

Next.js editor handler options
OptionDefaultPurpose
projectRootprocess.cwd()Project directory for content and configuration.
basePath"/_writenex"Full public editor URL, including the host basePath.
nextBasePath""Host basePath removed by Next.js before route handling.
contentDirs["content", "src/content"]Ordered discovery roots; the first matching collection wins.
trailingSlashunspecifiedMatch your Next.js preview URL convention.
maxBodyBytes10485760Request body limit, including multipart uploads.
allowProductionfalseEnable production editing with complete authentication.
remoteCmsconfig fileCMS authentication settings; keep credentials server-side.

If your Next.js site uses basePath: "/docs", keep the encoded route folder and configure both paths:

route.ts — host basePath example
const handler = createWritenexHandler({
  basePath: "/docs/_writenex",
  nextBasePath: "/docs",
  // Set trailingSlash: true if enabled in next.config.
});

Production & authentication

The editor returns 404 in production by default. Enable it only on a Node.js server with persistent writable storage and complete authentication.

route.ts — production opt-in
const handler = createWritenexHandler({
  allowProduction: true,
  remoteCms: { enabled: true },
});
Server environment variables
WRITENEX_CMS_USER=your-admin-username
WRITENEX_CMS_PASS=your-strong-password
WRITENEX_SECRET=your-long-random-signing-secret

Keep credentials server-side; never use NEXT_PUBLIC_ variables. Missing credentials or a signing secret keep the editor closed. Use HTTPS and preserve content, image, and .writenex/versions directories across deployments.

Edge runtime, static export, and read-only or ephemeral serverless storage cannot support durable editing. Installing this package on Vercel does not sync edits to Git. Pages Router and Git synchronization are not included.

Troubleshooting

404 in development
Check the literal %5Fwritenex directory, optional catch-all brackets, App Router location, and all route exports.
No collections
Create content/blog/ with Markdown or MDX files, or configure the exact collection path. Symlinks in editable paths are refused.
Missing editor assets
Wrap your existing config with withWritenex and match the handler basePath to the public URL.
Uploads return 413
Increase maxBodyBytes for the full multipart body and check your reverse proxy limits.
Changes to configuration do not appear
Restart the server after changing writenex.config.ts.