Appearance
Overview
This guide covers integrating Vibenv with Next.js 15 applications. The integration uses a custom server approach with the following key components:
- SWC Plugin - Injects component metadata (
data-component-file,data-component-name) at build time - Custom Server - Mounts vibe-server routes for AI agent communication
- Script Injection - Loads the vibe-agent UI during development
Prerequisites
- Node.js: Version 20.18.0 or higher
- Next.js: Version 15.x
- React: Version 19.x
- TypeScript: Version 5.x
1) Configure .npmrc for Vibenv packages
Vibenv ships as scoped packages from the Vibenv registry. Add this to your project-level .npmrc:
ini
@vibenv:registry=https://npm.vibenv.net/
legacy-peer-deps = trueThen authenticate with the Vibenv registry:
bash
npm login --scope @vibenvLogin details will be provided by the Vibenv team.
2) Install Vibenv dependencies
Install the required Vibenv packages:
bash
npm install @vibenv/vibe-agent @vibenv/framework-plugins @vibenv/logger @vibenv/platform @vibenv/constants @vibenv/swc-plugin @vibenv/transpiler-plugins @vibenv/vibe-server @vibenv/vite-plugins @vibenv/webpack-plugins3) Configure SWC Plugin
Create or update your next.config.ts to include the SWC plugin:
typescript
import type { NextConfig } from 'next';
import path from 'path';
const nextConfig: NextConfig = {
output: 'standalone',
experimental: {
swcPlugins: [[path.resolve(__dirname, '../../src/packages/swc-plugin/vibenv_swc_plugin.wasm'), {}]] as any
}
};
export default nextConfig;Important Notes:
- The SWC plugin path should be adjusted based on your monorepo structure
- SWC plugins are NOT supported in Turbopack yet
- Use
npm run dev(webpack) to enable SWC plugin functionality - Use
npm run dev:turbofor faster builds without SWC plugins
- Use
- The plugin adds
data-component-fileanddata-component-nameattributes to JSX elements
4) Create Custom Server with Vibe-Server Integration
Create server.mjs at your project root:
javascript
import { createServer } from 'http';
import { parse } from 'url';
import next from 'next';
import express from 'express';
// Vibe-server imports (conditionally loaded in development)
let routes = null;
let vibeServerAvailable = false;
// Try to load vibe-server (gracefully fail if not installed)
try {
const vibeServerModule = await import('@vibenv/vibe-server/routes.js');
routes = vibeServerModule.routes;
vibeServerAvailable = true;
} catch (error) {
console.warn(
'@vibenv/vibe-server not installed. Running without vibe-agent integration.'
);
console.warn(' To enable: npm install @vibenv/vibe-server @vibenv/constants @vibenv/cli-agents');
}
// Environment configuration
const dev = process.env.NODE_ENV !== 'production';
const hostname = process.env.HOSTNAME || 'localhost';
const port = parseInt(process.env.PORT || '3000', 10);
const enableVibeServer = dev && vibeServerAvailable && process.env.DISABLE_VIBE_SERVER !== 'true';
// Initialize Next.js app
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
/**
* Logger factory for vibe-server
* Creates a factory function that produces loggers with prefixes
*/
const createLoggerFactory = (basePrefix) => {
return (subPrefix) => ({
log: (...args) => console.log(`${basePrefix}${subPrefix}`, ...args),
error: (...args) => console.error(`${basePrefix}${subPrefix}`, ...args),
warn: (...args) => console.warn(`${basePrefix}${subPrefix}`, ...args)
});
};
/**
* Start the server
*/
app.prepare()
.then(() => {
const expressApp = express();
const server = createServer(expressApp);
// Vibe-Server Integration (Development Only)
if (enableVibeServer && routes) {
const loggerFactory = createLoggerFactory('[VIBENV]');
// Add JSON body parser for vibe-server routes
expressApp.use('/_vibe-agent', express.json());
// Mount vibe-server routes
expressApp.use('/_vibe-agent', routes(loggerFactory));
console.log('Vibe-server enabled');
console.log(' Routes available at: http://' + hostname + ':' + port + '/_vibe-agent');
}
// Next.js Request Handler (All Routes)
expressApp.all('*', (req, res) => {
const parsedUrl = parse(req.url, true);
return handle(req, res, parsedUrl);
});
// Start Server
server.listen(port, hostname, (err) => {
if (err) throw err;
console.log(`> Ready on http://${hostname}:${port}`);
});
// Graceful Shutdown
const gracefulShutdown = (signal) => {
console.log(`Received ${signal}, closing server gracefully...`);
server.close(() => {
console.log('Server closed');
process.exit(0);
});
setTimeout(() => {
console.error('Forcing server close after timeout');
process.exit(1);
}, 10000);
};
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
})
.catch((err) => {
console.error('Error starting server:', err);
process.exit(1);
});Update your package.json scripts:
json
{
"scripts": {
"dev": "node server.mjs",
"dev:next": "next dev",
"dev:turbo": "next dev --turbopack",
"build": "next build",
"start": "NODE_ENV=production node server.mjs"
}
}Vibe-Server Routes Available:
POST /_vibe-agent/prompt- Submit AI promptsGET /_vibe-agent/sse- Real-time updates via Server-Sent EventsGET /_vibe-agent/session-response- Get session stateGET /_vibe-agent/workspace/accept- Commit and push changesGET /_vibe-agent/workspace/drop- Discard changesGET /_vibe-agent/workspace/reset- Reset to main branchGET /_vibe-agent/kill- Kill agent process
5) Create VibeAgentScript Component
Create src/components/VibeAgentScript.tsx:
tsx
'use client';
import Script from 'next/script';
/**
* VibeAgentScript Component
*
* Injects the vibe-agent UI script into the application.
* The vibe-agent provides AI-powered development tools in the browser.
*/
export const VibeAgentScript = () => {
const isDevelopment = process.env.NODE_ENV === 'development';
const vibeAgentUrl = process.env.NEXT_PUBLIC_VIBE_AGENT_URL || 'http://localhost:5173/src/main.ts';
const disableVibeAgent = process.env.NEXT_PUBLIC_DISABLE_VIBE_AGENT === 'true';
// Don't load in production or if explicitly disabled
if (!isDevelopment || disableVibeAgent) {
return null;
}
return (
<Script
src={vibeAgentUrl}
type="module"
strategy="afterInteractive"
onError={(e) => {
console.warn(
'[VibeAgent] Failed to load vibe-agent script. ' +
'Make sure the vibe-agent dev server is running: ' +
'cd packages/vibe-agent && npm run dev'
);
}}
/>
);
};6) Update Root Layout
Update src/app/layout.tsx to include the VibeAgentScript component:
tsx
import type { ReactNode } from 'react';
import type { Metadata } from 'next';
import { VibeAgentScript } from '@/components/VibeAgentScript';
// ... other imports
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app'
};
const Layout = ({ children }: Readonly<{ children: ReactNode }>) => {
return (
<html suppressHydrationWarning lang='en'>
<body className="...">
{/* Your app content */}
{children}
<VibeAgentScript />
</body>
</html>
);
};
export default Layout;7) Environment Variables (Optional)
Create a .env file in your project root for local configuration:
bash
# Vibe-Agent Configuration
NEXT_PUBLIC_VIBE_AGENT_URL=http://localhost:5173/src/main.ts
NEXT_PUBLIC_DISABLE_VIBE_AGENT=false
# Vibe-Server Configuration
DISABLE_VIBE_SERVER=false
# Server Configuration
HOSTNAME=localhost
PORT=3000
NODE_ENV=development8) Optional: Set the CLI agent via .vibenv.js
Create .vibenv.js in your project root to control which CLI agent Vibenv uses:
javascript
module.exports = {
"cli-agent": "claude" // or "copilot"
};This file is read from the current working directory when Vibenv starts.
9) Start the Development Server
First, ensure the vibe-agent UI is running (in a separate terminal):
bash
cd packages/vibe-agent
npm run devThen start your Next.js application:
bash
npm run devYou should see:
- Vibenv logs in the console during compilation
- The Vibe-server routes available at
http://localhost:3000/_vibe-agent - Press
Shift+Vin the browser to toggle the Vibe-Agent UI
How Integration Works
SWC Plugin: During build, the SWC plugin injects
data-component-fileanddata-component-nameattributes into JSX elements, enabling the vibe-agent to identify components.Custom Server: The Express server in
server.mjs:- Mounts vibe-server routes at
/_vibe-agent/* - Works with both webpack and Turbopack
- Provides full Express middleware control
- Handles graceful shutdown
- Mounts vibe-server routes at
Script Injection: The
VibeAgentScriptcomponent:- Loads the vibe-agent UI from the Vite dev server (HMR enabled)
- Only runs in development
- Uses Next.js
Scriptcomponent for optimal loading
Troubleshooting
SWC Plugin Not Working
Issue: Component metadata attributes not appearing
Solutions:
- Ensure you're using
npm run dev(webpack), notnpm run dev:turbo - Verify the SWC plugin path is correct in
next.config.ts - Check that the WASM file exists at the specified path
Vibe-Server Routes Not Available
Issue: /_vibe-agent/* routes return 404
Solutions:
- Ensure
@vibenv/vibe-serveris installed - Check that you're using the custom server (
npm run dev, notnpm run dev:next) - Verify
DISABLE_VIBE_SERVERis not set totrue
Vibe-Agent UI Not Loading
Issue: Script fails to load or UI doesn't appear
Solutions:
- Ensure vibe-agent dev server is running:
cd packages/vibe-agent && npm run dev - Check
NEXT_PUBLIC_VIBE_AGENT_URLin.env - Verify
NEXT_PUBLIC_DISABLE_VIBE_AGENTis nottrue - Check browser console for script loading errors
Port Conflicts
Issue: Port 3000 already in use
Solutions:
- Change the port in
.env:PORT=3001 - Or kill the process using port 3000:
lsof -ti:3000 | xargs kill
Turbopack Limitations
Issue: SWC plugin doesn't work with Turbopack
Solution:
- This is a known limitation. Use
npm run devfor full Vibenv functionality - Use
npm run dev:turboonly for faster development without component metadata
TypeScript Configuration
Ensure your tsconfig.json includes the following:
json
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
},
"target": "ES2023"
}
}Next.js Configuration Options
The Next.js configuration in this integration uses:
output: 'standalone'- Enables standalone output for Docker deploymentexperimental.swcPlugins- Injects the Vibenv SWC plugin for component metadata
Production Considerations
- The vibe-agent and vibe-server are development-only tools
- In production, the
VibeAgentScriptcomponent returnsnull - The custom server can still be used in production (without vibe-server routes)
- For deployment, ensure
NODE_ENV=productionis set