Deploys applications to Vercel including serverless functions, edge functions, environment variables, and CI/CD. Use when deploying Next.js applications, frontend projects, or serverless APIs.
Deploys Next.js apps and serverless functions to Vercel. Use when you need to deploy a project, configure environment variables, set up CI/CD, or manage production/preview deployments.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
The frontend cloud platform for deploying web applications.
Install CLI:
npm i -g vercel
Deploy:
vercel
Deploy to production:
vercel --prod
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"],
"functions": {
"api/**/*.ts": {
"memory": 1024,
"maxDuration": 10
}
},
"rewrites": [
{ "source": "/api/:path*", "destination": "/api/:path*" }
],
"redirects": [
{ "source": "/old", "destination": "/new", "permanent": true }
],
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" }
]
}
]
}
Via Dashboard:
Via CLI:
vercel env add MY_VAR
vercel env ls
vercel env pull .env.local
// Production only
NEXT_PUBLIC_API_URL=https://api.example.com
// Preview (PR deployments)
NEXT_PUBLIC_API_URL=https://staging-api.example.com
// Development
NEXT_PUBLIC_API_URL=http://localhost:3001
// Next.js - server side
const apiKey = process.env.API_KEY;
// Next.js - client side (must be prefixed)
const publicUrl = process.env.NEXT_PUBLIC_API_URL;
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const users = await getUsers();
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const body = await request.json();
const user = await createUser(body);
return NextResponse.json(user, { status: 201 });
}
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === 'GET') {
const users = await getUsers();
return res.json(users);
}
if (req.method === 'POST') {
const user = await createUser(req.body);
return res.status(201).json(user);
}
res.setHeader('Allow', ['GET', 'POST']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
// api/hello.ts
import type { VercelRequest, VercelResponse } from '@vercel/node';
export default function handler(req: VercelRequest, res: VercelResponse) {
return res.json({ message: 'Hello from Vercel!' });
}
// app/api/heavy/route.ts
export const runtime = 'nodejs';
export const maxDuration = 60; // seconds
export const dynamic = 'force-dynamic';
export async function GET() {
// Long-running operation
}
// app/api/geo/route.ts
import { NextRequest, NextResponse } from 'next/server';
export const runtime = 'edge';
export async function GET(request: NextRequest) {
const country = request.geo?.country ?? 'Unknown';
const city = request.geo?.city ?? 'Unknown';
return NextResponse.json({
country,
city,
message: `Hello from ${city}, ${country}!`,
});
}
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Check auth
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
// Add headers
const response = NextResponse.next();
response.headers.set('x-custom-header', 'value');
return response;
}
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*'],
};
// app/posts/page.tsx
export const revalidate = 3600; // Revalidate every hour
async function getPosts() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 },
});
return res.json();
}
export default async function PostsPage() {
const posts = await getPosts();
return <PostList posts={posts} />;
}
// app/api/revalidate/route.ts
import { revalidatePath, revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const { path, tag, secret } = await request.json();
if (secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
}
if (path) {
revalidatePath(path);
}
if (tag) {
revalidateTag(tag);
}
return NextResponse.json({ revalidated: true });
}
{
"redirects": [
{ "source": "/blog/:slug", "destination": "/posts/:slug", "permanent": true },
{ "source": "/old-page", "destination": "/new-page", "statusCode": 301 }
],
"rewrites": [
{ "source": "/api/:path*", "destination": "https://api.example.com/:path*" },
{ "source": "/:path*", "destination": "/index.html" }
]
}
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/blog/:slug',
permanent: true,
},
];
},
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.backend.com/:path*',
},
];
},
};
# Every push to non-production branch creates preview
git push origin feature-branch
# Creates: feature-branch-abc123.vercel.app
# Via CLI
vercel --prod
# Via Git (push to main/master)
git push origin main
# Via CLI
vercel rollback [deployment-url]
# Via Dashboard
# Deployments > ... > Promote to Production
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
);
}
import { SpeedInsights } from '@vercel/speed-insights/next';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<SpeedInsights />
</body>
</html>
);
}
// vercel.json
{
"crons": [
{
"path": "/api/cron/daily",
"schedule": "0 0 * * *"
},
{
"path": "/api/cron/hourly",
"schedule": "0 * * * *"
}
]
}
// app/api/cron/daily/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Run daily task
await runDailyTask();
return NextResponse.json({ success: true });
}
| Mistake | Fix |
|---|---|
| Exposing secrets | Use env vars, not code |
| Large function bundles | Split into smaller functions |
| Missing NEXT_PUBLIC_ prefix | Prefix client-side vars |
| No error handling | Add try/catch in functions |
| Cold start issues | Use edge runtime when possible |
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.