Vercel Functions
Platform
Vercel Functions
Overview
Vercel Functions is an innovative serverless function execution environment provided by Vercel that seamlessly integrates with frontend applications, enabling easy construction of API endpoints, middleware, and backend processing. Through deep integration with modern web frameworks like Next.js, React, Vue.js, and Svelte, it significantly improves full-stack development efficiency. Supporting both Edge Runtime and Node.js Runtime, with developer experience-focused features like TypeScript, zero-configuration, and streaming support, it has gained attention as a core component of JAMstack architecture in 2025.
Details
Vercel Functions 2025 edition is experiencing rapid growth as a serverless computing platform for modern web development, particularly in Next.js and React applications. It provides an ideal environment for frontend developers with Edge Runtime's high-speed execution across 14 global edge locations, TypeScript native support, zero-configuration seamless deployment, and real-time streaming capabilities. With integration with Vercel AI SDK, it strongly supports AI application development and offers rich features to support team development such as Git-based workflows, preview deployments, and gradual rollouts.
Key Features
- Edge Runtime: High-speed execution at global edge locations
- Node.js Support: Complete support for traditional Node.js runtime
- TypeScript Native: Type-safe development environment
- Zero Configuration: Seamless deployment without configuration
- Streaming: Real-time data streaming support
- Next.js Integration: Full-stack development optimization
Advantages and Disadvantages
Advantages
- Improved development efficiency through perfect integration with Next.js ecosystem
- Global low-latency execution environment via Edge Runtime
- Type-safe development experience with TypeScript native support
- Git-based automatic deployment and preview features
- AI application development support through Vercel AI SDK integration
- Seamless scaling and operation with zero configuration
Disadvantages
- Strong dependency on Vercel platform and vendor lock-in
- Limited infrastructure control compared to other cloud providers
- Difficult cost prediction with unpredictable billing structure for high concurrent execution
- Node.js API limitations in Edge Runtime environment
- Lack of enterprise features and advanced customization options
- Functional constraints for complex backend logic
Reference Pages
Code Examples
Setup and Function Creation
# Install Vercel CLI
npm install -g vercel
# Initialize project and deploy
npx create-next-app@latest my-vercel-app
cd my-vercel-app
vercel
# Start local development server
vercel dev
// api/hello.js - Basic API function
export default function handler(req, res) {
console.log('Method:', req.method);
console.log('Query:', req.query);
console.log('Headers:', req.headers);
// CORS support
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
try {
const response = {
message: 'Hello from Vercel Functions!',
timestamp: new Date().toISOString(),
method: req.method,
query: req.query,
userAgent: req.headers['user-agent'] || 'Unknown'
};
res.status(200).json(response);
} catch (error) {
console.error('Function error:', error);
res.status(500).json({
error: 'Internal server error',
message: error.message
});
}
}
// api/users.ts - TypeScript API function with Edge Runtime
import { NextRequest, NextResponse } from 'next/server';
export const config = {
runtime: 'edge',
};
interface User {
id: string;
name: string;
email: string;
status: 'active' | 'inactive';
createdAt: string;
}
// In-memory store for demo (use database in production)
let users: User[] = [
{
id: '1',
name: 'John Doe',
email: '[email protected]',
status: 'active',
createdAt: new Date().toISOString()
}
];
export default async function handler(req: NextRequest) {
const { method, url } = req;
const { searchParams } = new URL(url);
// CORS headers
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
};
if (method === 'OPTIONS') {
return new NextResponse(null, { status: 200, headers });
}
try {
switch (method) {
case 'GET':
const status = searchParams.get('status');
const filteredUsers = status
? users.filter(user => user.status === status)
: users;
return NextResponse.json({
users: filteredUsers,
count: filteredUsers.length,
filters: { status }
}, { headers });
case 'POST':
const body = await req.json();
const newUser: User = {
id: Date.now().toString(),
name: body.name,
email: body.email,
status: 'active',
createdAt: new Date().toISOString()
};
users.push(newUser);
return NextResponse.json({
message: 'User created successfully',
user: newUser
}, { status: 201, headers });
case 'DELETE':
const userId = searchParams.get('id');
if (!userId) {
return NextResponse.json({
error: 'User ID is required'
}, { status: 400, headers });
}
users = users.filter(user => user.id !== userId);
return NextResponse.json({
message: 'User deleted successfully'
}, { headers });
default:
return NextResponse.json({
error: 'Method not allowed'
}, { status: 405, headers });
}
} catch (error) {
console.error('API Error:', error);
return NextResponse.json({
error: 'Internal server error',
message: error instanceof Error ? error.message : 'Unknown error'
}, { status: 500, headers });
}
}
HTTP APIs and Request Handling
// api/products/[id].ts - Dynamic route with parameter validation
import { NextApiRequest, NextApiResponse } from 'next';
import { z } from 'zod';
// Validation schemas
const ProductSchema = z.object({
name: z.string().min(1, 'Name is required'),
price: z.number().positive('Price must be positive'),
category: z.enum(['electronics', 'clothing', 'books', 'home']),
description: z.string().optional(),
inStock: z.boolean().default(true)
});
const QuerySchema = z.object({
id: z.string().regex(/^\d+$/, 'ID must be a number')
});
interface Product {
id: string;
name: string;
price: number;
category: string;
description?: string;
inStock: boolean;
updatedAt: string;
}
// Demo data store
let products: Product[] = [
{
id: '1',
name: 'Laptop Computer',
price: 999.99,
category: 'electronics',
description: 'High-performance laptop',
inStock: true,
updatedAt: new Date().toISOString()
}
];
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method, query } = req;
try {
// Validate query parameters
const { id } = QuerySchema.parse(query);
switch (method) {
case 'GET':
const product = products.find(p => p.id === id);
if (!product) {
return res.status(404).json({ error: 'Product not found' });
}
return res.status(200).json({ product });
case 'PUT':
const updateData = ProductSchema.partial().parse(req.body);
const productIndex = products.findIndex(p => p.id === id);
if (productIndex === -1) {
return res.status(404).json({ error: 'Product not found' });
}
products[productIndex] = {
...products[productIndex],
...updateData,
updatedAt: new Date().toISOString()
};
return res.status(200).json({
message: 'Product updated successfully',
product: products[productIndex]
});
case 'DELETE':
const deleteIndex = products.findIndex(p => p.id === id);
if (deleteIndex === -1) {
return res.status(404).json({ error: 'Product not found' });
}
products.splice(deleteIndex, 1);
return res.status(200).json({ message: 'Product deleted successfully' });
default:
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
return res.status(405).json({ error: 'Method not allowed' });
}
} catch (error) {
console.error('API Error:', error);
if (error instanceof z.ZodError) {
return res.status(400).json({
error: 'Validation error',
details: error.errors
});
}
return res.status(500).json({
error: 'Internal server error',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
}
// api/upload.ts - File upload handling
import { NextApiRequest, NextApiResponse } from 'next';
import formidable from 'formidable';
import fs from 'fs';
import path from 'path';
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const form = formidable({
maxFileSize: 10 * 1024 * 1024, // 10MB
uploadDir: './public/uploads',
keepExtensions: true,
});
const [fields, files] = await form.parse(req);
const uploadedFiles = Array.isArray(files.file) ? files.file : [files.file];
const results = [];
for (const file of uploadedFiles) {
if (file) {
const fileName = `${Date.now()}-${file.originalFilename}`;
const newPath = path.join('./public/uploads', fileName);
// Move file to permanent location
fs.renameSync(file.filepath, newPath);
results.push({
filename: fileName,
originalName: file.originalFilename,
size: file.size,
mimetype: file.mimetype,
url: `/uploads/${fileName}`
});
}
}
return res.status(200).json({
message: 'Files uploaded successfully',
files: results
});
} catch (error) {
console.error('Upload error:', error);
return res.status(500).json({
error: 'Upload failed',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
}
Database Integration and Data Processing
// api/database/users.ts - Prisma database integration
import { PrismaClient } from '@prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
const prisma = new PrismaClient();
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req;
try {
switch (method) {
case 'GET':
const { page = '1', limit = '10', search } = req.query;
const offset = (parseInt(page as string) - 1) * parseInt(limit as string);
const where = search ? {
OR: [
{ name: { contains: search as string, mode: 'insensitive' } },
{ email: { contains: search as string, mode: 'insensitive' } }
]
} : {};
const [users, total] = await Promise.all([
prisma.user.findMany({
where,
skip: offset,
take: parseInt(limit as string),
orderBy: { createdAt: 'desc' },
include: {
profile: true,
posts: {
select: { id: true, title: true, published: true }
}
}
}),
prisma.user.count({ where })
]);
return res.status(200).json({
users,
pagination: {
total,
page: parseInt(page as string),
limit: parseInt(limit as string),
pages: Math.ceil(total / parseInt(limit as string))
}
});
case 'POST':
const { name, email, profileData } = req.body;
const newUser = await prisma.user.create({
data: {
name,
email,
profile: profileData ? {
create: profileData
} : undefined
},
include: {
profile: true
}
});
return res.status(201).json({
message: 'User created successfully',
user: newUser
});
default:
return res.status(405).json({ error: 'Method not allowed' });
}
} catch (error) {
console.error('Database error:', error);
return res.status(500).json({
error: 'Database operation failed',
message: error instanceof Error ? error.message : 'Unknown error'
});
} finally {
await prisma.$disconnect();
}
}
// api/analytics/events.ts - Analytics data processing
import { NextApiRequest, NextApiResponse } from 'next';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!
);
interface AnalyticsEvent {
event_type: string;
user_id?: string;
session_id: string;
properties: Record<string, any>;
timestamp: string;
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const events: AnalyticsEvent[] = Array.isArray(req.body) ? req.body : [req.body];
// Validate events
const validatedEvents = events.map(event => ({
...event,
timestamp: event.timestamp || new Date().toISOString(),
properties: event.properties || {}
}));
// Batch insert to database
const { data, error } = await supabase
.from('analytics_events')
.insert(validatedEvents);
if (error) {
throw error;
}
// Process events for real-time analytics
await Promise.all(validatedEvents.map(async (event) => {
switch (event.event_type) {
case 'page_view':
await updatePageViewCounters(event);
break;
case 'user_action':
await updateUserEngagementMetrics(event);
break;
case 'conversion':
await updateConversionFunnels(event);
break;
}
}));
return res.status(200).json({
message: 'Events processed successfully',
count: validatedEvents.length
});
} catch (error) {
console.error('Analytics error:', error);
return res.status(500).json({
error: 'Failed to process analytics events',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
}
async function updatePageViewCounters(event: AnalyticsEvent) {
const { data, error } = await supabase
.from('page_analytics')
.upsert({
page_url: event.properties.page_url,
view_count: 1,
last_viewed: event.timestamp
}, {
onConflict: 'page_url',
ignoreDuplicates: false
});
if (error) {
console.error('Failed to update page view counters:', error);
}
}
async function updateUserEngagementMetrics(event: AnalyticsEvent) {
if (!event.user_id) return;
const { data, error } = await supabase
.from('user_engagement')
.upsert({
user_id: event.user_id,
action_type: event.properties.action,
action_count: 1,
last_action: event.timestamp
}, {
onConflict: 'user_id,action_type',
ignoreDuplicates: false
});
if (error) {
console.error('Failed to update user engagement:', error);
}
}
async function updateConversionFunnels(event: AnalyticsEvent) {
const { data, error } = await supabase
.from('conversion_events')
.insert({
user_id: event.user_id,
session_id: event.session_id,
funnel_step: event.properties.step,
conversion_value: event.properties.value || 0,
timestamp: event.timestamp
});
if (error) {
console.error('Failed to track conversion:', error);
}
}
Authentication and Security
// api/auth/login.ts - JWT authentication
import { NextApiRequest, NextApiResponse } from 'next';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const JWT_SECRET = process.env.JWT_SECRET!;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({
error: 'Email and password are required'
});
}
// Find user in database
const user = await prisma.user.findUnique({
where: { email },
include: { profile: true }
});
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify password
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate JWT token
const token = jwt.sign(
{
userId: user.id,
email: user.email,
role: user.role
},
JWT_SECRET,
{ expiresIn: '7d' }
);
// Generate refresh token
const refreshToken = jwt.sign(
{ userId: user.id },
JWT_SECRET + 'refresh',
{ expiresIn: '30d' }
);
// Update last login
await prisma.user.update({
where: { id: user.id },
data: { lastLoginAt: new Date() }
});
// Set secure HTTP-only cookie
res.setHeader('Set-Cookie', [
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=604800; Path=/`,
`refreshToken=${refreshToken}; HttpOnly; Secure; SameSite=Strict; Max-Age=2592000; Path=/`
]);
return res.status(200).json({
message: 'Login successful',
user: {
id: user.id,
name: user.name,
email: user.email,
role: user.role,
profile: user.profile
}
});
} catch (error) {
console.error('Login error:', error);
return res.status(500).json({
error: 'Authentication failed',
message: error instanceof Error ? error.message : 'Unknown error'
});
} finally {
await prisma.$disconnect();
}
}
// middleware.ts - Authentication middleware
import { NextRequest, NextResponse } from 'next/server';
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET!;
interface JWTPayload {
userId: string;
email: string;
role: string;
iat: number;
exp: number;
}
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Skip middleware for public routes
if (pathname.startsWith('/api/auth') ||
pathname.startsWith('/api/public') ||
pathname === '/api/health') {
return NextResponse.next();
}
// Check for authentication on protected routes
if (pathname.startsWith('/api/admin') ||
pathname.startsWith('/api/user')) {
const token = request.cookies.get('token')?.value;
if (!token) {
return NextResponse.json(
{ error: 'Authentication required' },
{ status: 401 }
);
}
try {
const payload = jwt.verify(token, JWT_SECRET) as JWTPayload;
// Check role-based access
if (pathname.startsWith('/api/admin') && payload.role !== 'admin') {
return NextResponse.json(
{ error: 'Insufficient permissions' },
{ status: 403 }
);
}
// Add user info to headers for API routes
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-user-id', payload.userId);
requestHeaders.set('x-user-email', payload.email);
requestHeaders.set('x-user-role', payload.role);
return NextResponse.next({
request: {
headers: requestHeaders,
}
});
} catch (error) {
return NextResponse.json(
{ error: 'Invalid token' },
{ status: 401 }
);
}
}
return NextResponse.next();
}
export const config = {
matcher: [
'/api/admin/:path*',
'/api/user/:path*',
'/api/protected/:path*'
]
};
Event-Driven Architecture
// api/webhooks/stripe.ts - Stripe webhook handling
import { NextApiRequest, NextApiResponse } from 'next';
import Stripe from 'stripe';
import { buffer } from 'micro';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2023-10-16',
});
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const buf = await buffer(req);
const sig = req.headers['stripe-signature']!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(buf, sig, webhookSecret);
} catch (err) {
console.error('Webhook signature verification failed:', err);
return res.status(400).json({ error: 'Invalid signature' });
}
try {
switch (event.type) {
case 'checkout.session.completed':
await handleCheckoutCompleted(event.data.object as Stripe.Checkout.Session);
break;
case 'invoice.payment_succeeded':
await handlePaymentSucceeded(event.data.object as Stripe.Invoice);
break;
case 'customer.subscription.updated':
await handleSubscriptionUpdated(event.data.object as Stripe.Subscription);
break;
case 'customer.subscription.deleted':
await handleSubscriptionCanceled(event.data.object as Stripe.Subscription);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
return res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
return res.status(500).json({
error: 'Webhook processing failed',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
}
async function handleCheckoutCompleted(session: Stripe.Checkout.Session) {
console.log('Processing checkout completion:', session.id);
// Update user subscription status
if (session.customer && session.subscription) {
const subscription = await stripe.subscriptions.retrieve(
session.subscription as string
);
// Update database with subscription info
// await updateUserSubscription(session.customer, subscription);
// Send welcome email
// await sendWelcomeEmail(session.customer_email);
// Track conversion event
await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/analytics/events`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event_type: 'conversion',
properties: {
step: 'subscription_created',
value: session.amount_total / 100,
currency: session.currency,
subscription_id: session.subscription
},
session_id: session.id,
timestamp: new Date().toISOString()
})
});
}
}
async function handlePaymentSucceeded(invoice: Stripe.Invoice) {
console.log('Processing successful payment:', invoice.id);
// Update payment records
// await recordPayment(invoice);
// Send receipt email
// await sendPaymentReceipt(invoice);
}
async function handleSubscriptionUpdated(subscription: Stripe.Subscription) {
console.log('Processing subscription update:', subscription.id);
// Update user subscription details
// await updateSubscriptionDetails(subscription);
// Handle plan changes
if (subscription.cancel_at_period_end) {
// Handle scheduled cancellation
console.log('Subscription scheduled for cancellation');
}
}
async function handleSubscriptionCanceled(subscription: Stripe.Subscription) {
console.log('Processing subscription cancellation:', subscription.id);
// Update user status
// await deactivateUserSubscription(subscription.customer);
// Send cancellation confirmation
// await sendCancellationEmail(subscription.customer);
}
Monitoring and Performance Optimization
// api/health.ts - Health check endpoint
import { NextApiRequest, NextApiResponse } from 'next';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
interface HealthStatus {
status: 'healthy' | 'unhealthy';
timestamp: string;
services: {
database: 'healthy' | 'unhealthy';
redis?: 'healthy' | 'unhealthy';
external_apis: 'healthy' | 'unhealthy';
};
metrics: {
response_time: number;
memory_usage: number;
uptime: number;
};
}
export default async function handler(req: NextApiRequest, res: NextApiResponse<HealthStatus>) {
const startTime = Date.now();
try {
// Check database connectivity
const dbHealthy = await checkDatabaseHealth();
// Check external APIs
const externalApisHealthy = await checkExternalApis();
// Calculate metrics
const responseTime = Date.now() - startTime;
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024; // MB
const uptime = process.uptime();
const allHealthy = dbHealthy && externalApisHealthy;
const healthStatus: HealthStatus = {
status: allHealthy ? 'healthy' : 'unhealthy',
timestamp: new Date().toISOString(),
services: {
database: dbHealthy ? 'healthy' : 'unhealthy',
external_apis: externalApisHealthy ? 'healthy' : 'unhealthy'
},
metrics: {
response_time: responseTime,
memory_usage: Math.round(memoryUsage * 100) / 100,
uptime: Math.round(uptime)
}
};
const statusCode = allHealthy ? 200 : 503;
return res.status(statusCode).json(healthStatus);
} catch (error) {
console.error('Health check error:', error);
const errorStatus: HealthStatus = {
status: 'unhealthy',
timestamp: new Date().toISOString(),
services: {
database: 'unhealthy',
external_apis: 'unhealthy'
},
metrics: {
response_time: Date.now() - startTime,
memory_usage: 0,
uptime: process.uptime()
}
};
return res.status(503).json(errorStatus);
}
}
async function checkDatabaseHealth(): Promise<boolean> {
try {
await prisma.$queryRaw`SELECT 1`;
return true;
} catch (error) {
console.error('Database health check failed:', error);
return false;
}
}
async function checkExternalApis(): Promise<boolean> {
try {
const checks = await Promise.allSettled([
fetch('https://api.stripe.com/v1', {
method: 'HEAD',
headers: { 'Authorization': `Bearer ${process.env.STRIPE_SECRET_KEY}` }
}),
// Add other external API checks as needed
]);
return checks.every(result =>
result.status === 'fulfilled' &&
result.value.ok
);
} catch (error) {
console.error('External API health check failed:', error);
return false;
}
}
// api/metrics.ts - Performance metrics collection
import { NextApiRequest, NextApiResponse } from 'next';
interface Metrics {
requests_per_minute: number;
average_response_time: number;
error_rate: number;
active_connections: number;
memory_usage: {
heap_used: number;
heap_total: number;
external: number;
rss: number;
};
cpu_usage: number;
}
// In-memory metrics store (use Redis in production)
const metricsStore = {
requests: [] as Array<{ timestamp: number; duration: number; status: number }>,
errors: [] as Array<{ timestamp: number; error: string }>,
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const now = Date.now();
const oneMinuteAgo = now - 60000;
// Filter recent requests
const recentRequests = metricsStore.requests.filter(
r => r.timestamp > oneMinuteAgo
);
const recentErrors = metricsStore.errors.filter(
e => e.timestamp > oneMinuteAgo
);
// Calculate metrics
const requestsPerMinute = recentRequests.length;
const averageResponseTime = recentRequests.length > 0
? recentRequests.reduce((sum, r) => sum + r.duration, 0) / recentRequests.length
: 0;
const errorRate = requestsPerMinute > 0
? (recentErrors.length / requestsPerMinute) * 100
: 0;
// Memory usage
const memoryUsage = process.memoryUsage();
// CPU usage (simplified calculation)
const cpuUsage = await getCpuUsage();
const metrics: Metrics = {
requests_per_minute: requestsPerMinute,
average_response_time: Math.round(averageResponseTime * 100) / 100,
error_rate: Math.round(errorRate * 100) / 100,
active_connections: 0, // Would need to track this
memory_usage: {
heap_used: Math.round(memoryUsage.heapUsed / 1024 / 1024 * 100) / 100,
heap_total: Math.round(memoryUsage.heapTotal / 1024 / 1024 * 100) / 100,
external: Math.round(memoryUsage.external / 1024 / 1024 * 100) / 100,
rss: Math.round(memoryUsage.rss / 1024 / 1024 * 100) / 100,
},
cpu_usage: cpuUsage
};
return res.status(200).json(metrics);
} catch (error) {
console.error('Metrics collection error:', error);
return res.status(500).json({
error: 'Failed to collect metrics',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
}
async function getCpuUsage(): Promise<number> {
return new Promise((resolve) => {
const startUsage = process.cpuUsage();
const startTime = process.hrtime();
setTimeout(() => {
const currentUsage = process.cpuUsage(startUsage);
const currentTime = process.hrtime(startTime);
const elapsedTime = currentTime[0] * 1000000 + currentTime[1] / 1000; // microseconds
const cpuPercent = (currentUsage.user + currentUsage.system) / elapsedTime * 100;
resolve(Math.round(cpuPercent * 100) / 100);
}, 100);
});
}
// Middleware to track requests (would be used in middleware.ts)
export function trackRequest(duration: number, status: number) {
metricsStore.requests.push({
timestamp: Date.now(),
duration,
status
});
// Keep only last 1000 requests
if (metricsStore.requests.length > 1000) {
metricsStore.requests = metricsStore.requests.slice(-1000);
}
}
export function trackError(error: string) {
metricsStore.errors.push({
timestamp: Date.now(),
error
});
// Keep only last 100 errors
if (metricsStore.errors.length > 100) {
metricsStore.errors = metricsStore.errors.slice(-100);
}
}
Vercel Functions provides a powerful serverless computing platform that perfectly integrates with modern web development workflows, enabling developers to build scalable full-stack applications with minimal configuration and maximum performance.