Add ?edit=true to any URL. Log in with a magic link. Edit headlines, CTAs, and copy directly on the page. Vercel redeploys automatically on publish.
Scroll to reveal the demo
Works with the stack you already use
How it works
Six steps from install to live editing. No database, no third-party CMS, no pipeline changes.
npm install @editlayer/nextRun one command to install and scaffold. The CLI creates the API routes and config file automatically. Nothing to build from scratch.
<EditableText id="...">Wrap any headline, paragraph, or link with EditableText. Keep your existing className and styles. EditLayer wraps around them, never rewrites them.
4 env varsAdd your secret, site URL, Resend API key, and GitHub token to Vercel. Push to GitHub. That's the entire backend.
?edit=trueVisit yoursite.com/?edit=true. Enter your email, click the magic link. Green outlines appear on every editable field immediately.
git commitClick any field to edit inline. See the live preview as you type. Save a draft to share, or hit Publish to commit directly to GitHub.
zero infraPublishing writes editlayer/content.json to your repo via the GitHub API. Vercel detects the commit and redeploys automatically.
Setup guide
Copy, paste, deploy. Every command and env var you need. Nothing more.
# Inside your Next.js project npm install @editlayer/next npx editlayer init # Creates editlayer.config.ts, editlayer/content.json, # and scaffolds the API routes in app/api/editlayer/
# .env.local — and add to Vercel → Settings → Environment Variables # Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" EDITLAYER_SECRET=your-32-char-random-secret EDITLAYER_SITE_URL=https://yoursite.com # Magic link emails — free tier at resend.com EDITLAYER_RESEND_API_KEY=re_xxxxxxxxxxxx EDITLAYER_EMAIL_FROM=EditLayer <edit@yoursite.com> # Who can log in and publish vs. draft-only EDITLAYER_OWNERS=owner@yoursite.com EDITLAYER_EDITORS=marketing@yoursite.com # GitHub fine-grained token — repo contents read/write EDITLAYER_GITHUB_TOKEN=github_pat_xxxx EDITLAYER_GITHUB_REPO=yourname/your-repo
Open Cursor, start a new chat, and paste the prompt below. The agent will wrap your layout, find every hardcoded string, and convert them to <EditableText> components across your entire project.
I have installed @editlayer/next (v0.3.1) in this Next.js App Router project. Your task is to complete the full integration following the exact pattern documented below. Do not deviate from these conventions.
━━ PACKAGE OVERVIEW ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@editlayer/next is a self-hosted visual editing layer. It reads content from
editlayer/content.json at build time and writes back to it via GitHub API on publish.
There is no database, no external dashboard, and no CMS. All configuration is via
environment variables already added to .env.local and Vercel.
━━ STEP 1: ENSURE API ROUTES EXIST ━━━━━━━━━━━━━━━━━━━━
Check whether app/api/editlayer/ exists with these route files:
login/route.ts, verify/route.ts, session/route.ts,
logout/route.ts, publish/route.ts, drafts/route.ts
If any are missing, run: npx editlayer init
Each route file must export the corresponding handler from @editlayer/next/server:
// app/api/editlayer/login/route.ts
export { handleEditLayerLogin as POST } from "@editlayer/next/server"
// app/api/editlayer/verify/route.ts
export { handleEditLayerVerify as GET } from "@editlayer/next/server"
// app/api/editlayer/session/route.ts
export { handleEditLayerSession as GET } from "@editlayer/next/server"
// app/api/editlayer/logout/route.ts
export { handleEditLayerLogout as POST } from "@editlayer/next/server"
// app/api/editlayer/publish/route.ts
export { handleEditLayerPublish as POST } from "@editlayer/next/server"
// app/api/editlayer/drafts/route.ts
export { handleEditLayerDrafts as GET, handleEditLayerDrafts as POST } from "@editlayer/next/server"
━━ STEP 2: WRAP ROOT LAYOUT ━━━━━━━━━━━━━━━━━━━━━━━━━━━
Open app/layout.tsx. Add the provider wrapper:
import { EditLayerProvider } from "@editlayer/next"
import { loadEditLayerContent } from "@editlayer/next/server"
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const content = await loadEditLayerContent()
return (
<html lang="en">
<body>
<EditLayerProvider content={content}>
{children}
</EditLayerProvider>
</body>
</html>
)
}
Do not remove any existing providers or imports — wrap them inside EditLayerProvider.
━━ STEP 3: MARK EDITABLE CONTENT ━━━━━━━━━━━━━━━━━━━━━━
Scan every .tsx and .jsx file in app/ and components/ for hardcoded marketing copy:
- h1, h2, h3, h4 headings
- p paragraph text (marketing, not UI labels)
- Button/link labels, nav item labels, CTA text
- Section titles, feature names, testimonial quotes
- Footer text
Convert each to EditableText using this exact pattern:
BEFORE: <h1 className="...">Your headline here</h1>
AFTER: <EditableText id="home.hero.title" as="h1" className="...">Your headline here</EditableText>
BEFORE: <p className="...">Subheading copy</p>
AFTER: <EditableText id="home.hero.subtitle" as="p" className="...">Subheading copy</EditableText>
ID naming convention: "[page].[section].[field]"
Examples: home.hero.title, home.hero.cta, pricing.header.subtitle,
about.team.description, nav.cta.label, footer.tagline
Import at top of each file:
import { EditableText, EditableLink } from "@editlayer/next"
For anchor tags and buttons with href:
BEFORE: <a href="/contact" className="...">Book a call</a>
AFTER: <EditableLink id="home.hero.cta" href="/contact" className="...">Book a call</EditableLink>
IMPORTANT RULES:
- Keep all existing className, style, and other props untouched
- Only replace the text node, not the element structure
- Do not wrap complex children (icons + text) — only wrap pure text strings
- Do not touch code comments, console.log strings, or non-visible strings
━━ STEP 4: UPDATE content.json ━━━━━━━━━━━━━━━━━━━━━━━━
Create or update editlayer/content.json with the default value for every field you marked:
{
"version": 1,
"fields": {
"home.hero.title": "Your original headline text",
"home.hero.subtitle": "Your original subheading text",
...all other fields you converted...
},
"meta": {
"updatedAt": "[current ISO timestamp]",
"updatedBy": "init",
"commitSha": null
}
}
━━ DONE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
After completing all steps, tell me:
1. How many fields were marked editable across how many files
2. Any files you skipped and why
3. Confirm the API routes are in place// app/layout.tsx import { EditLayerProvider } from "@editlayer/next" import { loadEditLayerContent } from "@editlayer/next/server" export default async function RootLayout({ children }) { const content = await loadEditLayerContent() return ( <html><body> <EditLayerProvider content={content}> {children} </EditLayerProvider> </body></html> ) }
// Any component — wrap static copy, keep everything else import { EditableText, EditableLink } from "@editlayer/next" export function Hero() { return ( <section> <EditableText id="home.hero.title" as="h1"> Your original headline </EditableText> <EditableText id="home.hero.sub" as="p"> Your original subheadline </EditableText> <EditableLink id="home.hero.cta" href="/contact"> Book a call </EditableLink> </section> ) }
# Push to GitHub — Vercel deploys automatically git add . git commit -m "Add EditLayer" git push # Then visit your live site with ?edit=true # → Enter your owner email # → Click the magic link in your inbox # → Green outlines appear on every editable field # → Click any field, edit, Save Draft or Publish # → Publish commits content.json → Vercel redeploys
What you get
Built for developers who want to hand editing control to their clients, without handing over their codebase.
Email-only login with short-lived signed tokens. No passwords, no OAuth config. HTTP-only cookies for sessions.
Green outlines on hover. Click to open an inline editor. Live preview of changes before publishing.
Publishing commits content.json to your repo. Vercel detects the push and redeploys. Zero extra infra.
Owners publish. Editors save drafts. Add team members via env vars. No database required.
Origin validation, rate limiting, field ID allowlists, content sanitization. Plain text only, no arbitrary HTML.
No CMS subscription. No hosted service. No vendor lock-in. Just an npm package and your existing Vercel project.
FAQ
Everything you need to know before installing.
Start today
Your marketing team won't need to open a code editor just to change a headline. Give them the power to edit, safely.