Edge Functions
Deploy serverless functions globally with zero cold starts and automatic scaling.
Overview
Edge Functions run your code on the edge, close to your users. They support TypeScript and JavaScript with full npm package support.
<50ms Cold Start
Functions stay warm at the edge
Auto Scaling
Scale to millions of requests
TypeScript Native
Full TypeScript + npm support
Creating Functions
Function Structure
Functions are organized in the functions/ directory:
my-project/
├── functions/
│ ├── hello-world/
│ │ └── index.ts
│ ├── api/
│ │ ├── users/
│ │ │ └── index.ts
│ │ └── orders/
│ │ └── index.ts
│ └── webhooks/
│ └── stripe/
│ └── index.ts
└── lubes.jsonBasic Function
functions/hello-world/index.ts
import { serve } from '@lubes/functions'
serve(async (req) => {
const { name } = await req.json()
return Response.json({
message: `Hello, ${name || 'World'}!`,
timestamp: new Date().toISOString(),
})
})Function with Database Access
functions/api/users/index.ts
import { serve } from '@lubes/functions'
import { db } from '@lubes/db'
serve(async (req) => {
const url = new URL(req.url)
const userId = url.searchParams.get('id')
if (!userId) {
return Response.json(
{ error: 'User ID required' },
{ status: 400 }
)
}
const user = await db.queryOne`
SELECT id, name, email, created_at
FROM users
WHERE id = ${userId}
`
if (!user) {
return Response.json(
{ error: 'User not found' },
{ status: 404 }
)
}
return Response.json({ user })
})HTTP Methods
import { serve } from '@lubes/functions'
import { db } from '@lubes/db'
serve(async (req) => {
const { method } = req
switch (method) {
case 'GET':
const users = await db.query`SELECT * FROM users`
return Response.json({ users })
case 'POST':
const body = await req.json()
const newUser = await db.queryOne`
INSERT INTO users (name, email)
VALUES (${body.name}, ${body.email})
RETURNING *
`
return Response.json({ user: newUser }, { status: 201 })
case 'DELETE':
const url = new URL(req.url)
const id = url.searchParams.get('id')
await db.query`DELETE FROM users WHERE id = ${id}`
return Response.json({ success: true })
default:
return Response.json(
{ error: 'Method not allowed' },
{ status: 405 }
)
}
})Deploying Functions
Deploy a Single Function
# Deploy a specific function
lubes functions deploy hello-world
# Output:
# Deploying function 'hello-world'...
# Building... done
# Uploading... done
# Function deployed successfully!
# URL: https://abc123.functions.lubes.dev/hello-worldDeploy All Functions
# Deploy all functions in the project
lubes functions deploy --all
# Deploy with verbose output
lubes functions deploy --all --verboseManage Functions
# List all deployed functions
lubes functions list
# Get function details
lubes functions info hello-world
# Delete a function
lubes functions delete hello-world
# View function versions
lubes functions versions hello-world
# Rollback to previous version
lubes functions rollback hello-world --version 3Environment Variables
Securely store API keys, secrets, and configuration using environment variables. Variables are encrypted at rest and injected at runtime.
Setting Variables
# Set a single variable
lubes env set STRIPE_SECRET_KEY sk_live_xxx
# Set multiple variables from a file
lubes env set --file .env.production
# Set variables for a specific environment
lubes env set --env staging API_URL https://staging-api.example.comUsing Variables in Functions
import { serve } from '@lubes/functions'
serve(async (req) => {
// Access environment variables
const stripeKey = Deno.env.get('STRIPE_SECRET_KEY')
const apiUrl = Deno.env.get('API_URL')
// Use in your function logic
const response = await fetch(`${apiUrl}/webhook`, {
headers: {
'Authorization': `Bearer ${stripeKey}`
}
})
return Response.json({ success: true })
})Managing Variables
# List all variables
lubes env list
# Get a specific variable (value hidden)
lubes env get STRIPE_SECRET_KEY
# Remove a variable
lubes env remove OLD_API_KEY
# Copy variables between environments
lubes env copy --from production --to stagingLogs & Debugging
Viewing Logs
# Stream logs in real-time
lubes functions logs hello-world --follow
# View last 100 log lines
lubes functions logs hello-world --lines 100
# Filter by time range
lubes functions logs hello-world --since 1h
# Filter by log level
lubes functions logs hello-world --level errorLogging in Functions
import { serve } from '@lubes/functions'
serve(async (req) => {
// Standard console methods work
console.log('Request received:', req.method, req.url)
console.info('Processing request...')
console.warn('Deprecated field used')
console.error('Something went wrong:', error)
// Structured logging
console.log(JSON.stringify({
event: 'user_action',
userId: '123',
action: 'login',
metadata: { ip: req.headers.get('x-forwarded-for') }
}))
return Response.json({ success: true })
})Local Development
# Start local development server
lubes functions serve
# Serve a specific function
lubes functions serve hello-world
# Serve with custom port
lubes functions serve --port 3001
# Serve with environment file
lubes functions serve --env-file .env.localAdvanced Topics
CORS Configuration
import { serve, cors } from '@lubes/functions'
serve(async (req) => {
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return cors(req, new Response(null, { status: 204 }))
}
const response = Response.json({ data: 'hello' })
return cors(req, response, {
origin: ['https://example.com', 'https://app.example.com'],
methods: ['GET', 'POST'],
headers: ['Content-Type', 'Authorization'],
})
})Authentication
import { serve } from '@lubes/functions'
import { verifyJwt } from '@lubes/auth'
serve(async (req) => {
// Get token from header
const token = req.headers.get('Authorization')?.replace('Bearer ', '')
if (!token) {
return Response.json(
{ error: 'Authentication required' },
{ status: 401 }
)
}
// Verify JWT
const { user, error } = await verifyJwt(token)
if (error) {
return Response.json(
{ error: 'Invalid token' },
{ status: 401 }
)
}
// User is authenticated
return Response.json({
message: `Hello, ${user.email}!`,
userId: user.id
})
})