Next.js
Next has no plugin API, so quello cannot arrive the way it does everywhere else. What it can do is put the same code behind three one-line imports — one for each file Next insists the project owns.
Install
pnpm add -D @quello/next
Configure
import { withQuello } from '@quello/next/config'
export default withQuello({
// your config, untouched
})
That is the whole setup. On the next next dev, withQuello writes your agent file, adds
.quello/ to .gitignore, creates the route handler for you, and prints where everything went:
quello press alt+q to pick
picks .quello/picks.json
endpoint /api/quello/picks
agent AGENTS.md
created app/api/quello/[...quello]/route.ts
Render it
One tag, once, in the root layout:
import { Quello } from '@quello/next'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Quello />
</body>
</html>
)
}
<Quello /> is a Server Component that renders a script tag, not a client component that
imports the picker. Nothing from @quello/core enters your client bundle — not even as a chunk
nobody loads — and in a production build the component renders null.
Props override next.config for a one-off:
<Quello shortcut="ctrl+shift+p" htmlMode="full" />
The route handler
withQuello writes this for you. It is here so you know what it is:
import { quelloRoute } from '@quello/next/route'
export const dynamic = 'force-dynamic'
export const { GET, HEAD, POST, PUT, DELETE, OPTIONS } = quelloRoute()
It serves two things below /api/quello: picks, which reads and writes .quello/picks.json, and
client.js, the runtime itself. Together they are what the Vite plugin's dev-server middleware does
elsewhere.
Why it cannot be one line, like Nuxt
Nuxt builds on Vite, so vite-plugin-quello gets the dev server's middleware stack, a virtual
module and a dev-only mode for free, and the project writes one import. Next gives a package none of
those:
- it runs its own dev server, so there is no
setupMiddlewaresto add the picks endpoint to — the only place Next accepts an HTTP handler from you is a route file in your ownapp/; - it renders HTML with its own renderer, so there is no
transformIndexHtmland nohtml-webpack-pluginto add the script tag through; - it has no plugin API at all.
next.configis the only file Next evaluates on your behalf, and from Next 16 thewebpack()escape hatch is gone under Turbopack anyway.
So the shape here — a component and a route — is not a workaround. It is the only shape that survives a bundler change, which is why the package builds on it rather than on a webpack hook.
Options
Every plugin option works, plus two of Next's own. Pass them to
withQuello as a second argument, or to <Quello /> as props.
| Option | Default | |
|---|---|---|
basePath | /api/quello | Where the route handler is mounted. |
scaffoldRoute | true | Create the route file when it is missing. |
enabled behaves slightly differently here than in the plugins: it can only ever turn quello
off. Production is off regardless — the endpoint writes to disk, so it must not exist outside
next dev.
Pages Router
Same idea, one file:
import { quelloApiConfig, quelloApiRoute } from '@quello/next/route'
// quello reads the body itself, so Next must not parse it first.
export const config = quelloApiConfig
export default quelloApiRoute()
Then render <Quello /> in pages/_document.tsx, inside <body>.
What a pick will know
The component name, and the source file when the bundler's frames carry one:
{ "framework": { "framework": "react", "component": "OverviewPage", "file": "app/page.tsx" } }
Server Components are included — app/layout.tsx comes back for an element rendered there.
That is the webpack answer, which is what next dev gives you up to Next 15. From Next 16
Turbopack is the default, and its stack frames name the chunk holding a module
(/_next/static/chunks/_0ltyzvd._.js) rather than the source. quello drops those frames instead of
reporting a bundle as your source file, so a pick there looks like this:
{ "framework": { "framework": "react", "component": "OverviewPage" } }
The component name, the selector and the DOM path all still lead to the code.
package.json names, and React 19
removed _debugSource in favour of owner stacks: an Error captured where each element was
written. quello reads the file out of that stack, but not the line — a stack frame addresses the
compiled module, and a browser does not run error.stack through source maps, so page.tsx:22
there is not line 22 of page.tsx. A file the agent can search beats a line number that quietly
points at the wrong element. Resolving frames through Next's own
/__nextjs_original-stack-frame would fix that, and is
on the roadmap.An element written inside a dependency — the <a> that next/link renders — reports the component
and no file, which is the honest answer: it is not in your code.