Vercel Edge Deployment
Deploy your MoroJS applications to Vercel Edge Runtime for ultra-fast performance and global distribution with zero cold starts.
Quick Start
MoroJS provides native support for Vercel Edge Runtime with the same API you use for Node.js development.
Basic Edge Function
typescript
1// api/hello.ts
2import { createAppEdge } from '@morojs/moro';
3
4const app = createAppEdge();
5
6app.get('/', () => {
7 return { message: 'Hello from Vercel Edge!' };
8});
9
10app.post('/users', {
11 body: z.object({
12 name: z.string(),
13 email: z.string().email()
14 }),
15 handler: ({ body }) => {
16 return {
17 success: true,
18 user: body
19 };
20 }
21});
22
23// Export for Vercel
24export default app.getHandler();
25
26// Optional: Export specific HTTP methods
27export const GET = app.getHandler();
28export const POST = app.getHandler();
Edge Runtime Benefits
- • Zero cold start latency
- • Global edge deployment
- • Automatic scaling
- • Smaller bundle sizes
- • Enhanced security
Project Structure
Recommended Project Structure
typescript
1my-moro-app/
2├── api/
3│ ├── auth/
4│ │ ├── login.ts
5│ │ └── callback.ts
6│ ├── users/
7│ │ ├── index.ts
8│ │ └── [id].ts
9│ └── hello.ts
10├── lib/
11│ ├── auth.ts
12│ ├── db.ts
13│ └── utils.ts
14├── package.json
15├── vercel.json
16└── tsconfig.json
17
18// package.json
19{
20 "name": "my-moro-app",
21 "version": "1.0.0",
22 "scripts": {
23 "dev": "vercel dev",
24 "build": "tsc",
25 "deploy": "vercel"
26 },
27 "dependencies": {
28 "@morojs/moro": "^1.0.0",
29 "zod": "^3.22.0"
30 },
31 "devDependencies": {
32 "@vercel/node": "^3.0.0",
33 "typescript": "^5.0.0",
34 "vercel": "^32.0.0"
35 }
36}
37
38// vercel.json
39{
40 "functions": {
41 "api/**/*.ts": {
42 "runtime": "@vercel/edge"
43 }
44 },
45 "regions": ["all"]
46}
Advanced Edge Configuration
Edge-Optimized Application
typescript
1// api/app.ts
2import { createAppEdge } from '@morojs/moro';
3import { z } from 'zod';
4
5const app = createAppEdge({
6 // Edge-specific configuration
7 runtime: {
8 // Memory limit for edge function
9 memory: 128, // MB
10
11 // Maximum execution duration
12 maxDuration: 30, // seconds
13
14 // Regions to deploy to
15 regions: ['iad1', 'sfo1', 'fra1'], // or 'all'
16 },
17
18 // CORS for edge
19 cors: {
20 origin: ['https://myapp.com', 'https://admin.myapp.com'],
21 credentials: false // Cookies not supported in edge
22 },
23
24 // Edge-compatible features only
25 features: {
26 // File system not available in edge
27 fileSystem: false,
28
29 // Streaming responses supported
30 streaming: true,
31
32 // WebCrypto API available
33 crypto: true
34 }
35});
36
37// Global middleware for edge
38app.use(async (context, next) => {
39 // Add edge-specific headers
40 context.response.headers.set('X-Edge-Runtime', 'vercel');
41 context.response.headers.set('X-Edge-Region', process.env.VERCEL_REGION || 'unknown');
42
43 await next();
44});
45
46// Geolocation-aware routing
47app.get('/api/location', {
48 handler: ({ request }) => {
49 // Access Vercel edge headers
50 const country = request.headers.get('x-vercel-ip-country') || 'unknown';
51 const city = request.headers.get('x-vercel-ip-city') || 'unknown';
52 const region = request.headers.get('x-vercel-ip-country-region') || 'unknown';
53
54 return {
55 country,
56 city,
57 region,
58 timezone: request.headers.get('x-vercel-ip-timezone'),
59 latitude: request.headers.get('x-vercel-ip-latitude'),
60 longitude: request.headers.get('x-vercel-ip-longitude')
61 };
62 }
63});
64
65export default app.getHandler();
Edge Database Integration
typescript
1// lib/edge-db.ts
2import { createClient } from '@planetscale/database';
3
4// Edge-compatible database clients
5const db = createClient({
6 url: process.env.DATABASE_URL
7});
8
9// Redis for edge (Upstash)
10import { Redis } from '@upstash/redis';
11
12const redis = new Redis({
13 url: process.env.UPSTASH_REDIS_REST_URL,
14 token: process.env.UPSTASH_REDIS_REST_TOKEN
15});
16
17// api/users/[id].ts
18import { createAppEdge } from '@morojs/moro';
19import { db, redis } from '../../lib/edge-db';
20
21const app = createAppEdge();
22
23app.get('/api/users/:id', {
24 params: z.object({
25 id: z.string().uuid()
26 }),
27 handler: async ({ params }) => {
28 // Try cache first
29 const cached = await redis.get(`user:${params.id}`);
30 if (cached) {
31 return JSON.parse(cached);
32 }
33
34 // Query database
35 const result = await db.execute(
36 'SELECT id, name, email FROM users WHERE id = ?',
37 [params.id]
38 );
39
40 const user = result.rows[0];
41 if (user) {
42 // Cache for 5 minutes
43 await redis.setex(`user:${params.id}`, 300, JSON.stringify(user));
44 }
45
46 return user || { error: 'User not found' };
47 }
48});
49
50export default app.getHandler();
Environment Variables
Environment Configuration
typescript
1// .env.local (for development)
2DATABASE_URL=mysql://user:pass@host/db
3UPSTASH_REDIS_REST_URL=https://...
4UPSTASH_REDIS_REST_TOKEN=...
5JWT_SECRET=your-secret-key
6VERCEL_ENV=development
7
8// lib/config.ts
9const config = {
10 database: {
11 url: process.env.DATABASE_URL!
12 },
13 redis: {
14 url: process.env.UPSTASH_REDIS_REST_URL!,
15 token: process.env.UPSTASH_REDIS_REST_TOKEN!
16 },
17 auth: {
18 jwtSecret: process.env.JWT_SECRET!
19 },
20 vercel: {
21 env: process.env.VERCEL_ENV || 'development',
22 region: process.env.VERCEL_REGION || 'local'
23 }
24};
25
26export default config;
27
28// Vercel CLI commands for environment variables
29// vercel env add JWT_SECRET production
30// vercel env add DATABASE_URL production
31// vercel env pull .env.local
Deployment Process
Deploy to Vercel
typescript
1# Install Vercel CLI
2npm install -g vercel
3
4# Login to Vercel
5vercel login
6
7# Deploy from project directory
8vercel
9
10# Or deploy with specific configuration
11vercel --prod
12
13# Deploy with environment variables
14vercel --prod --env DATABASE_URL=@database-url
15
16# GitHub Integration (automatic deployments)
17# 1. Connect your GitHub repository to Vercel
18# 2. Push to main branch triggers production deployment
19# 3. Push to other branches triggers preview deployments
20
21# Package.json scripts for easy deployment
22{
23 "scripts": {
24 "dev": "vercel dev",
25 "build": "tsc",
26 "deploy:preview": "vercel",
27 "deploy:prod": "vercel --prod",
28 "logs": "vercel logs"
29 }
30}
GitHub Actions Deployment
typescript
1# .github/workflows/deploy.yml
2name: Deploy to Vercel
3
4on:
5 push:
6 branches: [main]
7 pull_request:
8 branches: [main]
9
10jobs:
11 deploy:
12 runs-on: ubuntu-latest
13
14 steps:
15 - uses: actions/checkout@v3
16
17 - name: Setup Node.js
18 uses: actions/setup-node@v3
19 with:
20 node-version: '18'
21 cache: 'npm'
22
23 - name: Install dependencies
24 run: npm ci
25
26 - name: Build project
27 run: npm run build
28
29 - name: Deploy to Vercel
30 uses: amondnet/vercel-action@v25
31 with:
32 vercel-token: ${{ secrets.VERCEL_TOKEN }}
33 vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
34 vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
35 vercel-args: '--prod'
36 if: github.ref == 'refs/heads/main'
Monitoring & Analytics
Edge Function Monitoring
typescript
1// api/metrics.ts
2import { createAppEdge } from '@morojs/moro';
3
4const app = createAppEdge();
5
6// Performance monitoring middleware
7app.use(async (context, next) => {
8 const start = Date.now();
9
10 await next();
11
12 const duration = Date.now() - start;
13 const region = process.env.VERCEL_REGION || 'unknown';
14
15 // Log performance metrics
16 console.log(JSON.stringify({
17 timestamp: new Date().toISOString(),
18 method: context.request.method,
19 path: context.request.url,
20 duration,
21 region,
22 status: context.response.status
23 }));
24
25 // Add performance headers
26 context.response.headers.set('X-Response-Time', `${duration}ms`);
27 context.response.headers.set('X-Edge-Region', region);
28});
29
30// Health check endpoint
31app.get('/api/health', {
32 handler: () => {
33 return {
34 status: 'healthy',
35 timestamp: new Date().toISOString(),
36 region: process.env.VERCEL_REGION,
37 runtime: 'edge'
38 };
39 }
40});
41
42export default app.getHandler();
43
44// Vercel Analytics integration
45import { track } from '@vercel/analytics';
46
47app.post('/api/events', {
48 body: z.object({
49 event: z.string(),
50 properties: z.record(z.any()).optional()
51 }),
52 handler: ({ body }) => {
53 // Track custom events
54 track(body.event, body.properties);
55
56 return { success: true };
57 }
58});