Skip to main content
Best practices for Edge Compute based on production patterns and common issues.

Configuration

Use Environment Variables for Secrets

Never hardcode secrets. Use the secrets API:
telnyx-edge secrets add --name API_KEY --value "sk-..."
Access in code:
const apiKey = process.env.API_KEY;

Set Appropriate Timeouts

Configure timeouts based on your function’s needs:
# func.toml
[edge_compute]
timeout_seconds = 30  # Default: 30, Max: 300

Use Descriptive Function Names

Function names become part of your URL. Choose wisely:
# ✅ Good
telnyx-edge new-func --name=user-api
telnyx-edge new-func --name=webhook-handler

# ❌ Bad
telnyx-edge new-func --name=func1
telnyx-edge new-func --name=test

Performance

Reuse Connections

Initialize clients once at module level, not per request:
// ✅ Good — client initialized once, reused across requests
const client = new HttpClient({ timeout: 5000 });

export async function handler(request) {
    const response = await client.get('https://api.example.com/data');
    return new Response(JSON.stringify(response));
}
// ❌ Bad — new client created every request
export async function handler(request) {
    const client = new HttpClient({ timeout: 5000 });
    const response = await client.get('https://api.example.com/data');
    return new Response(JSON.stringify(response));
}

Minimize Cold Starts

Cold starts happen when a new container spins up. Reduce their impact:
  1. Lazy-load dependencies — Only import what you need, when you need it
  2. Keep functions small — Smaller code = faster load
  3. Use lightweight frameworks — Hono over Express, FastAPI over Django
// ✅ Good — lazy load heavy dependency
let heavyLib;
function getHeavyLib() {
    if (!heavyLib) {
        heavyLib = require('heavy-library');
    }
    return heavyLib;
}

export async function handler(request) {
    if (needsHeavyProcessing(request)) {
        const lib = getHeavyLib();
        // use lib
    }
}

Cache Expensive Operations

Use KV for caching API responses and computed data:
async function getUser(userId) {
    // Check cache first
    const cached = await kv.get(`user:${userId}`);
    if (cached) return JSON.parse(cached);
    
    // Fetch from origin
    const user = await fetchUserFromDB(userId);
    
    // Cache for 5 minutes
    await kv.put(`user:${userId}`, JSON.stringify(user), { ttl: 300 });
    
    return user;
}

Reliability

Handle Errors Gracefully

Always return proper error responses:
export async function handler(request) {
    try {
        const data = await riskyOperation();
        return new Response(JSON.stringify(data), {
            headers: { "Content-Type": "application/json" }
        });
    } catch (error) {
        console.error("Operation failed:", error.message);
        
        return new Response(JSON.stringify({
            error: "Internal server error",
            requestId: request.headers.get("X-Request-ID")
        }), {
            status: 500,
            headers: { "Content-Type": "application/json" }
        });
    }
}

Set Timeouts on External Calls

Don’t let slow external services hang your function:
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);

try {
    const response = await fetch('https://api.example.com/data', {
        signal: controller.signal
    });
    clearTimeout(timeout);
    return response;
} catch (error) {
    if (error.name === 'AbortError') {
        return new Response('External service timeout', { status: 504 });
    }
    throw error;
}

Implement Retries with Backoff

For critical operations, add retry logic:
async function fetchWithRetry(url, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            const response = await fetch(url);
            if (response.ok) return response;
            
            // Don't retry client errors
            if (response.status < 500) throw new Error(`HTTP ${response.status}`);
        } catch (error) {
            if (i === maxRetries - 1) throw error;
            
            // Exponential backoff
            await new Promise(r => setTimeout(r, Math.pow(2, i) * 100));
        }
    }
}

Security

Validate Input

Never trust user input:
export async function handler(request) {
    const body = await request.json();
    
    // Validate required fields
    if (!body.email || typeof body.email !== 'string') {
        return new Response(JSON.stringify({ error: 'Invalid email' }), {
            status: 400
        });
    }
    
    // Validate format
    if (!isValidEmail(body.email)) {
        return new Response(JSON.stringify({ error: 'Invalid email format' }), {
            status: 400
        });
    }
    
    // Sanitize
    const email = body.email.toLowerCase().trim();
    // ...
}

Use HTTPS for External Calls

Always use HTTPS when calling external services:
// ✅ Good
await fetch('https://api.example.com/data');

// ❌ Bad — insecure
await fetch('http://api.example.com/data');

Don’t Log Sensitive Data

Be careful what you log:
// ✅ Good — log request metadata
console.log(`Request: ${request.method} ${request.url}`);

// ❌ Bad — logging secrets
console.log(`API Key: ${process.env.API_KEY}`);

// ❌ Bad — logging full request body (may contain PII)
console.log(`Body: ${JSON.stringify(body)}`);

Observability

Add Request IDs

Track requests through your system:
export async function handler(request) {
    const requestId = request.headers.get('X-Request-ID') || crypto.randomUUID();
    
    console.log(`[${requestId}] Processing request`);
    
    // Include in response
    return new Response(JSON.stringify({ data }), {
        headers: {
            "Content-Type": "application/json",
            "X-Request-ID": requestId
        }
    });
}

Log at Appropriate Levels

Use log levels effectively:
const logger = {
    debug: (msg) => process.env.LOG_LEVEL === 'debug' && console.log(`[DEBUG] ${msg}`),
    info: (msg) => console.log(`[INFO] ${msg}`),
    warn: (msg) => console.warn(`[WARN] ${msg}`),
    error: (msg) => console.error(`[ERROR] ${msg}`)
};

// Use appropriately
logger.debug(`Cache hit for key: ${key}`);      // Verbose debugging
logger.info(`User ${userId} created`);           // Normal operations
logger.warn(`Retry attempt ${i} for ${url}`);    // Concerning but handled
logger.error(`Database connection failed`);      // Errors requiring attention