Netlify Edge คืออะไร
Netlify Edge Functions เป็น serverless functions ที่รันบน edge network ของ Netlify ใช้ Deno runtime ทำให้ code รันใกล้กับผู้ใช้มากที่สุด ลด latency อย่างมากเมื่อเทียบกับ traditional serverless ที่รันใน region เดียว
ข้อดีของ Edge Functions ได้แก่ Low Latency รันใกล้ผู้ใช้ทั่วโลก response time ต่ำกว่า 50ms, Deno Runtime ใช้ TypeScript/JavaScript ที่ทันสมัย, Zero Cold Start ไม่มี cold start เหมือน traditional Lambda, Middleware Pattern transform requests/responses ก่อนถึง origin, Geolocation ใช้ข้อมูลตำแหน่งผู้ใช้ได้ทันที และ A/B Testing ทำ feature flags และ split testing ที่ edge
Tech Conference 2026 trends สำหรับ edge computing ได้แก่ Edge-first architectures แทน cloud-first, AI inference at the edge ลด latency สำหรับ ML predictions, Edge databases (Turso, Neon, PlanetScale) ฐานข้อมูลที่ replicate ไป edge, Streaming SSR server-side rendering ที่ edge และ Edge-native frameworks เช่น Astro, SvelteKit, Next.js ที่ optimize สำหรับ edge deployment
ติดตั้งและใช้งาน Netlify Edge Functions
เริ่มต้นใช้งาน Edge Functions
# === Netlify Edge Functions Setup ===
# 1. Install Netlify CLI
npm install -g netlify-cli
# 2. Create Project
mkdir edge-app && cd edge-app
npm init -y
# 3. Project Structure
# edge-app/
# ├── netlify/
# │ └── edge-functions/
# │ ├── hello.ts
# │ ├── geolocation.ts
# │ ├── ab-test.ts
# │ └── auth.ts
# ├── public/
# │ └── index.html
# ├── netlify.toml
# └── package.json
# 4. netlify.toml Configuration
cat > netlify.toml << 'EOF'
[build]
publish = "public"
[[edge_functions]]
path = "/api/hello"
function = "hello"
[[edge_functions]]
path = "/api/geo"
function = "geolocation"
[[edge_functions]]
path = "/*"
function = "ab-test"
[[edge_functions]]
path = "/dashboard/*"
function = "auth"
EOF
# 5. Basic Edge Function
cat > netlify/edge-functions/hello.ts << 'TSEOF'
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const url = new URL(request.url);
const name = url.searchParams.get("name") || "World";
return new Response(
JSON.stringify({
message: `Hello, !`,
timestamp: new Date().toISOString(),
geo: {
city: context.geo.city,
country: context.geo.country?.code,
latitude: context.geo.latitude,
longitude: context.geo.longitude,
},
server: {
region: Deno.env.get("DENO_REGION") || "unknown",
},
}),
{
headers: { "Content-Type": "application/json" },
}
);
};
TSEOF
# 6. Geolocation Edge Function
cat > netlify/edge-functions/geolocation.ts << 'TSEOF'
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const { city, country, latitude, longitude, timezone } = context.geo;
// Personalize content based on location
const greeting = getLocalGreeting(country?.code || "US");
const currency = getCurrency(country?.code || "US");
return new Response(
JSON.stringify({
greeting,
location: { city, country: country?.code, latitude, longitude, timezone },
currency,
nearestCDN: context.server?.region,
}),
{ headers: { "Content-Type": "application/json" } }
);
};
function getLocalGreeting(countryCode: string): string {
const greetings: Record = {
TH: "สวัสดี",
JP: "",
KR: "",
US: "Hello",
DE: "Hallo",
FR: "Bonjour",
};
return greetings[countryCode] || "Hello";
}
function getCurrency(countryCode: string): string {
const currencies: Record = {
TH: "THB", US: "USD", JP: "JPY", GB: "GBP", EU: "EUR",
};
return currencies[countryCode] || "USD";
}
TSEOF
# 7. Test locally
netlify dev
# 8. Deploy
netlify deploy --prod
echo "Edge functions deployed"
สร้าง Edge-First Applications
Patterns สำหรับ edge-first architecture
// === Edge-First Application Patterns ===
// 1. A/B Testing at Edge
// netlify/edge-functions/ab-test.ts
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const url = new URL(request.url);
// Skip for non-HTML requests
if (!url.pathname.endsWith("/") && !url.pathname.endsWith(".html")) {
return;
}
// Get or create experiment cookie
const cookies = parseCookies(request.headers.get("cookie") || "");
let variant = cookies["ab-variant"];
if (!variant) {
variant = Math.random() < 0.5 ? "A" : "B";
}
// Get the response from origin
const response = await context.next();
const html = await response.text();
// Modify HTML based on variant
let modifiedHtml = html;
if (variant === "B") {
modifiedHtml = html
.replace("Sign Up Free", "Start Your Free Trial")
.replace("bg-blue-600", "bg-green-600");
}
// Return modified response with cookie
const headers = new Headers(response.headers);
headers.set("Set-Cookie", `ab-variant=; Path=/; Max-Age=604800`);
headers.set("X-AB-Variant", variant);
return new Response(modifiedHtml, {
status: response.status,
headers,
});
};
function parseCookies(cookieStr: string): Record {
const cookies: Record = {};
cookieStr.split(";").forEach((pair) => {
const [key, value] = pair.trim().split("=");
if (key) cookies[key] = value || "";
});
return cookies;
}
// 2. Authentication Middleware
// netlify/edge-functions/auth.ts
// import type { Context } from "https://edge.netlify.com";
// import { jwtVerify } from "https://deno.land/x/jose@v4.14.4/index.ts";
//
// const JWT_SECRET = new TextEncoder().encode(Deno.env.get("JWT_SECRET"));
//
// export default async (request: Request, context: Context) => {
// const token = request.headers.get("Authorization")?.replace("Bearer ", "");
//
// if (!token) {
// return new Response(JSON.stringify({ error: "Unauthorized" }), {
// status: 401,
// headers: { "Content-Type": "application/json" },
// });
// }
//
// try {
// const { payload } = await jwtVerify(token, JWT_SECRET);
//
// // Add user info to request headers for downstream
// request.headers.set("X-User-ID", payload.sub as string);
// request.headers.set("X-User-Role", payload.role as string);
//
// return context.next();
// } catch {
// return new Response(JSON.stringify({ error: "Invalid token" }), {
// status: 403,
// headers: { "Content-Type": "application/json" },
// });
// }
// };
// 3. Rate Limiting at Edge
// netlify/edge-functions/rate-limit.ts
// const rateLimitMap = new Map();
//
// export default async (request: Request, context: Context) => {
// const ip = context.ip;
// const now = Date.now();
// const windowMs = 60000; // 1 minute
// const maxRequests = 100;
//
// let entry = rateLimitMap.get(ip);
//
// if (!entry || now > entry.resetAt) {
// entry = { count: 0, resetAt: now + windowMs };
// rateLimitMap.set(ip, entry);
// }
//
// entry.count++;
//
// if (entry.count > maxRequests) {
// return new Response(JSON.stringify({ error: "Rate limit exceeded" }), {
// status: 429,
// headers: {
// "Content-Type": "application/json",
// "Retry-After": "60",
// "X-RateLimit-Limit": maxRequests.toString(),
// "X-RateLimit-Remaining": "0",
// },
// });
// }
//
// const response = await context.next();
// response.headers.set("X-RateLimit-Remaining",
// (maxRequests - entry.count).toString());
// return response;
// };
Performance Optimization ด้วย Edge
เพิ่ม performance ด้วย edge computing
// === Edge Performance Optimization ===
// 1. Smart Caching at Edge
// netlify/edge-functions/cache.ts
import type { Context } from "https://edge.netlify.com";
const CACHE_DURATION: Record = {
"/api/products": 300, // 5 minutes
"/api/categories": 3600, // 1 hour
"/api/config": 86400, // 1 day
};
export default async (request: Request, context: Context) => {
const url = new URL(request.url);
const cacheDuration = CACHE_DURATION[url.pathname];
if (!cacheDuration) {
return context.next();
}
// Check cache
const cacheKey = ``;
const cached = await getCachedResponse(cacheKey);
if (cached) {
return new Response(cached.body, {
headers: {
...cached.headers,
"X-Cache": "HIT",
"X-Cache-Age": cached.age.toString(),
},
});
}
// Fetch from origin
const response = await context.next();
const body = await response.text();
// Store in cache
await setCachedResponse(cacheKey, body, cacheDuration);
return new Response(body, {
status: response.status,
headers: {
...Object.fromEntries(response.headers),
"X-Cache": "MISS",
"Cache-Control": `public, max-age=`,
},
});
};
// Simple in-memory cache (use KV store in production)
const cache = new Map; expiresAt: number }>();
async function getCachedResponse(key: string) {
const entry = cache.get(key);
if (!entry || Date.now() > entry.expiresAt) {
cache.delete(key);
return null;
}
return {...entry, age: Math.floor((entry.expiresAt - Date.now()) / 1000) };
}
async function setCachedResponse(key: string, body: string, ttl: number) {
cache.set(key, {
body,
headers: { "Content-Type": "application/json" },
expiresAt: Date.now() + ttl * 1000,
});
}
// 2. Image Optimization at Edge
// Redirect to optimized image based on device
// export default async (request: Request, context: Context) => {
// const url = new URL(request.url);
//
// if (!url.pathname.startsWith("/images/")) return context.next();
//
// const ua = request.headers.get("user-agent") || "";
// const acceptHeader = request.headers.get("accept") || "";
//
// // Detect WebP/AVIF support
// let format = "jpg";
// if (acceptHeader.includes("image/avif")) format = "avif";
// else if (acceptHeader.includes("image/webp")) format = "webp";
//
// // Detect device type for sizing
// const isMobile = /mobile|android|iphone/i.test(ua);
// const width = isMobile ? 640 : 1280;
//
// // Rewrite to CDN with transformations
// const optimizedUrl = `https://cdn.example.com?w=&fmt=&q=80`;
//
// return Response.redirect(optimizedUrl, 302);
// };
// 3. Performance Headers
// export default async (request: Request, context: Context) => {
// const response = await context.next();
//
// // Security headers
// response.headers.set("X-Content-Type-Options", "nosniff");
// response.headers.set("X-Frame-Options", "DENY");
// response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
//
// // Performance headers
// response.headers.set("X-DNS-Prefetch-Control", "on");
//
// // Server timing
// response.headers.set("Server-Timing",
// `edge;dur=1, region;desc=""`);
//
// return response;
// };
Advanced Edge Patterns
Patterns ขั้นสูงสำหรับ edge
// === Advanced Edge Patterns ===
// 1. Feature Flags at Edge
import type { Context } from "https://edge.netlify.com";
interface FeatureFlag {
enabled: boolean;
percentage: number;
regions?: string[];
}
const FEATURE_FLAGS: Record = {
"new-checkout": { enabled: true, percentage: 50, regions: ["US", "TH"] },
"dark-mode": { enabled: true, percentage: 100 },
"ai-search": { enabled: true, percentage: 20, regions: ["US"] },
};
function isFeatureEnabled(flag: string, userId: string, country: string): boolean {
const config = FEATURE_FLAGS[flag];
if (!config || !config.enabled) return false;
if (config.regions && !config.regions.includes(country)) return false;
// Deterministic hash for consistent assignment
const hash = simpleHash(`:`);
return (hash % 100) < config.percentage;
}
function simpleHash(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash |= 0;
}
return Math.abs(hash);
}
export default async (request: Request, context: Context) => {
const cookies = Object.fromEntries(
(request.headers.get("cookie") || "").split(";")
.map(c => c.trim().split("="))
);
const userId = cookies["user_id"] || crypto.randomUUID();
const country = context.geo.country?.code || "US";
const flags: Record = {};
for (const [name] of Object.entries(FEATURE_FLAGS)) {
flags[name] = isFeatureEnabled(name, userId, country);
}
// Inject flags into response
const response = await context.next();
const html = await response.text();
const flagScript = ``;
const modifiedHtml = html.replace("", ``);
return new Response(modifiedHtml, {
status: response.status,
headers: response.headers,
});
};
// 2. Edge-Side Includes (ESI)
// Compose page from multiple edge-cached fragments
// async function renderWithESI(html: string, context: Context) {
// const esiPattern = / /g;
// let result = html;
// let match;
//
// while ((match = esiPattern.exec(html)) !== null) {
// const [tag, src] = match;
// try {
// const fragment = await fetch(new URL(src, context.url));
// const fragmentHtml = await fragment.text();
// result = result.replace(tag, fragmentHtml);
// } catch {
// result = result.replace(tag, "");
// }
// }
//
// return result;
// }
// 3. Personalization Engine
// export default async (request: Request, context: Context) => {
// const { country, city, timezone } = context.geo;
// const language = request.headers.get("Accept-Language")?.split(",")[0] || "en";
//
// const personalization = {
// locale: language,
// currency: getCurrency(country?.code),
// timezone: timezone,
// promotions: getLocalPromotions(country?.code),
// };
//
// const response = await context.next();
// response.headers.set("X-Personalization", JSON.stringify(personalization));
// return response;
// };
Deployment และ Monitoring
Deploy และ monitor edge functions
# === Netlify Edge Deployment & Monitoring ===
# 1. Deploy Commands
# ===================================
# Deploy to preview
netlify deploy
# Deploy to production
netlify deploy --prod
# Deploy from CI/CD (GitHub Actions)
cat >.github/workflows/deploy.yml << 'EOF'
name: Deploy to Netlify
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v3
with:
publish-dir: './dist'
production-branch: main
production-deploy: true
env:
NETLIFY_AUTH_TOKEN: }
NETLIFY_SITE_ID: }
EOF
# 2. Monitoring Edge Functions
# ===================================
# Netlify Dashboard > Functions > Edge Functions
# Metrics available:
# - Invocations count
# - Average duration
# - Error rate
# - P95/P99 latency
# 3. Custom Logging
cat > netlify/edge-functions/logged.ts << 'TSEOF'
import type { Context } from "https://edge.netlify.com";
export default async (request: Request, context: Context) => {
const start = Date.now();
const requestId = crypto.randomUUID();
console.log(JSON.stringify({
type: "request",
requestId,
method: request.method,
url: request.url,
ip: context.ip,
country: context.geo.country?.code,
userAgent: request.headers.get("user-agent"),
}));
try {
const response = await context.next();
const duration = Date.now() - start;
console.log(JSON.stringify({
type: "response",
requestId,
status: response.status,
duration_ms: duration,
}));
response.headers.set("X-Request-ID", requestId);
response.headers.set("Server-Timing", "edge;dur=" + duration);
return response;
} catch (error) {
console.error(JSON.stringify({
type: "error",
requestId,
error: error.message,
duration_ms: Date.now() - start,
}));
return new Response("Internal Server Error", { status: 500 });
}
};
TSEOF
# 4. Performance Testing
# ===================================
# Test edge function latency from different regions
# Using curl with timing
curl -w "\nDNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
-s -o /dev/null https://your-site.netlify.app/api/hello
# Load test with hey
# hey -n 1000 -c 50 https://your-site.netlify.app/api/hello
echo "Edge deployment and monitoring configured"
FAQ คำถามที่พบบ่อย
Q: Edge Functions กับ Serverless Functions ต่างกันอย่างไร?
A: Edge Functions รันบน edge network (200+ locations ทั่วโลก) ใช้ Deno runtime มี zero cold start latency ต่ำมาก (1-5ms overhead) เหมาะสำหรับ request transformation, personalization, A/B testing Serverless Functions รันใน specific region (เช่น us-east-1) ใช้ Node.js runtime มี cold start (100-500ms) แต่มี compute resources มากกว่า เหมาะสำหรับ database queries, API calls, heavy computation ใช้ Edge Functions สำหรับ lightweight middleware ใช้ Serverless สำหรับ backend logic
Q: Netlify Edge Functions มี limitations อะไร?
A: Memory limit 512MB, CPU time limit 50ms per invocation (wall time ไม่จำกัด), response body size 40MB, ไม่มี persistent storage ที่ edge (ต้องใช้ external KV store), ไม่รองรับ Node.js APIs ทั้งหมด (ใช้ Deno runtime), pricing based on invocations (free tier 1M/month) สำหรับ heavy computation ใช้ Serverless Functions แทน
Q: Edge computing trends ที่ควรจับตาในปี 2026?
A: AI at the Edge รัน small ML models ที่ edge สำหรับ real-time predictions, Edge Databases เช่น Turso (SQLite at edge), Neon (Postgres with edge cache), PlanetScale ที่ replicate ไปทุก region, WebAssembly (Wasm) at Edge ใช้ languages อื่นนอกจาก JS/TS, Edge-native frameworks ที่ออกแบบมาสำหรับ edge deployment โดยเฉพาะ และ Edge Observability tools สำหรับ monitor distributed edge workloads
Q: ควรใช้ Netlify Edge กับ framework ไหน?
A: Astro ดีที่สุดสำหรับ content sites มี built-in edge rendering, SvelteKit มี Netlify adapter ที่ดี รองรับ edge SSR, Next.js ใช้ Netlify Next.js Runtime รองรับ middleware ที่ edge, Remix มี Netlify adapter รองรับ edge functions, Nuxt ใช้ Nitro engine ที่ deploy ไป edge ได้ ทุก framework ที่ output static HTML ทำงานบน Netlify CDN ได้อยู่แล้ว Edge Functions เพิ่ม dynamic capabilities เข้ามา