
Next
Embed OAuth emulators in a Next.js App Router app so preview deployments keep same-origin callbacks without rewriting redirect URLs.
Install
npx skills add https://github.com/vercel-labs/emulate --skill nextWhat is this skill?
- Install @emulators/adapter-next plus per-provider @emulators/* packages for smaller serverless bundles
- createEmulateHandler catch-all route exports GET, POST, PUT, PATCH, DELETE for App Router
- Same-origin OAuth solves changing callback URLs on Vercel preview deployments
- Supports Auth.js and NextAuth configuration with embedded emulators
- withEmulate wraps next.config for emulator-aware Next.js builds
Adoption & trust: 70 installs on skills.sh; 1.3k GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Frontend Designanthropics/skills
Vercel React Best Practicesvercel-labs/agent-skills
Remotion Best Practicesremotion-dev/skills
Vercel Composition Patternsvercel-labs/agent-skills
Develop Userscriptsxixu-me/skills
Next Best Practicesvercel-labs/next-skills
Journey fit
Primary fit
Emulator setup is integration work while building auth and local/preview parity in a Next.js product. adapter-next, catch-all route handlers, and withEmulate are framework integration tasks, not launch distribution or ship security audits.
Common Questions / FAQ
Is Next safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Next
# Next.js Integration The `@emulators/adapter-next` package embeds emulators directly into a Next.js App Router app, running them on the same origin. This is particularly useful for Vercel preview deployments where OAuth callback URLs change with every deployment. ## Install ```bash npm install @emulators/adapter-next @emulators/github @emulators/google ``` Only install the emulators you need. Each `@emulators/*` package is published independently, keeping serverless bundles small. ## Route Handler Create a catch-all route that serves emulator traffic: ```typescript // app/emulate/[...path]/route.ts import { createEmulateHandler } from '@emulators/adapter-next' import * as github from '@emulators/github' import * as google from '@emulators/google' export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({ services: { github: { emulator: github, seed: { users: [{ login: 'octocat', name: 'The Octocat' }], repos: [{ owner: 'octocat', name: 'hello-world', auto_init: true }], }, }, google: { emulator: google, seed: { users: [{ email: 'test@example.com', name: 'Test User' }], }, }, }, }) ``` This creates the following routes: - `/emulate/github/**` serves the GitHub emulator - `/emulate/google/**` serves the Google emulator ## Auth.js / NextAuth Configuration Point your provider at the emulator paths on the same origin: ```typescript import GitHub from 'next-auth/providers/github' const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000' GitHub({ clientId: 'any-value', clientSecret: 'any-value', authorization: { url: `${baseUrl}/emulate/github/login/oauth/authorize` }, token: { url: `${baseUrl}/emulate/github/login/oauth/access_token` }, userinfo: { url: `${baseUrl}/emulate/github/user` }, }) ``` No `oauth_apps` need to be seeded. When none are configured, the emulator skips `client_id`, `client_secret`, and `redirect_uri` validation. ## Font Tracing for Serverless Emulator UI pages use bundled fonts. Wrap your Next.js config to include them in the serverless trace: ```typescript // next.config.mjs import { withEmulate } from '@emulators/adapter-next' export default withEmulate({ // your normal Next.js config }) ``` If you mount the catch-all at a custom path, pass the matching prefix: ```typescript export default withEmulate(nextConfig, { routePrefix: '/api/emulate' }) ``` ## Persistence By default, emulator state is in-memory and resets on every cold start. To persist state across restarts, pass a `persistence` adapter. ### Custom Adapter (Vercel KV, Redis, etc.) ```typescript import { createEmulateHandler } from '@emulators/adapter-next' import * as github from '@emulators/github' const kvAdapter = { async load() { return await kv.get('emulate-state') }, async save(data: string) { await kv.set('emulate-state', data) }, } export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({ services: { github: { emulator: github } }, persistence: kvAdapter, }) ``` ### File Persistence (Local Dev) For local development, `@emulators/core` ships a file-based adapter: ```typescript import { filePersistence } from '@emulators/core' // persists to a JSON file persistence: filePersistence