Files
2nd/10_Wiki/Topic_Programming/Coding/Backend_Edge_Functions.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

8.9 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
backend-edge-functions Edge Functions — Cloudflare / Vercel / Deno Deploy Coding draft B conceptual 2026-05-09 2026-05-09
backend
edge
serverless
vibe-coding
language applicable_to
TS
Backend
Cloudflare Workers
Vercel Edge
Deno Deploy
edge runtime
V8 isolate
Wasm edge

Edge Functions

사용자 가까이 (300+ region) 실행. Cloudflare Workers / Vercel Edge / Deno Deploy / Fastly Compute@Edge. V8 isolate (cold start ms), 작은 limit.

📖 핵심 개념

  • V8 Isolate: process 안 — 매 request fast.
  • Web Standard: Request / Response / fetch.
  • Limits: CPU / memory / time 작음.
  • Storage: KV / D1 / Durable Object / R2.

💻 코드 패턴

Cloudflare Workers

// src/index.ts
export interface Env {
  DB: D1Database;
  CACHE: KVNamespace;
  BUCKET: R2Bucket;
}

export default {
  async fetch(req: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(req.url);
    
    if (url.pathname === '/api/users/me') {
      const userId = await getUserId(req);
      
      const cached = await env.CACHE.get(`user:${userId}`, { type: 'json' });
      if (cached) return Response.json(cached);
      
      const user = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();
      ctx.waitUntil(env.CACHE.put(`user:${userId}`, JSON.stringify(user), { expirationTtl: 60 }));
      
      return Response.json(user);
    }
    
    return new Response('Not found', { status: 404 });
  },
};
# wrangler.toml
name = "my-api"
main = "src/index.ts"
compatibility_date = "2024-12-01"

[[d1_databases]]
binding = "DB"
database_name = "my-app"
database_id = "..."

[[kv_namespaces]]
binding = "CACHE"
id = "..."

[[r2_buckets]]
binding = "BUCKET"
bucket_name = "uploads"

[observability]
enabled = true
wrangler dev
wrangler deploy

Vercel Edge Function

// app/api/users/route.ts
import { type NextRequest } from 'next/server';

export const runtime = 'edge';

export async function GET(req: NextRequest) {
  const id = req.nextUrl.searchParams.get('id');
  return Response.json({ id });
}
// 또는 standalone
// pages/api/edge.ts
export const config = { runtime: 'edge' };

export default function handler(req: Request) {
  return new Response('Hello from edge');
}

Deno Deploy

import { Hono } from 'hono';

const app = new Hono();
app.get('/', (c) => c.text('Hello from Deno Deploy'));

Deno.serve(app.fetch);
deployctl deploy --project=my-app src/index.ts

Bun on edge (Fly.io / Railway)

Bun = full Node API + Web Standard.
Fly / Railway 가 Bun runtime 지원.
Edge X but 가까운 region.

KV (Cloudflare)

// 빠른 read (eventually consistent globally)
await env.KV.put('key', 'value', { expirationTtl: 3600 });
const v = await env.KV.get('key');
const json = await env.KV.get('key', { type: 'json' });

// List
const list = await env.KV.list({ prefix: 'user:' });

// Stream large
const stream = await env.KV.get('large-file', { type: 'stream' });

→ Read 빠름 (각 region cache), write 글로벌 propagate (1-60s).

D1 (SQLite at edge)

const r = await env.DB.prepare('SELECT * FROM users WHERE email = ?')
  .bind('a@b.com')
  .first();

// Multi
const all = await env.DB.prepare('SELECT * FROM users WHERE status = ?')
  .bind('active')
  .all();

// Batch (transaction)
await env.DB.batch([
  env.DB.prepare('INSERT INTO users VALUES (?, ?)').bind(id1, email1),
  env.DB.prepare('INSERT INTO users VALUES (?, ?)').bind(id2, email2),
]);

Durable Objects (글로벌 state)

// Counter — 한 instance per name, 글로벌 단일
export class Counter {
  state: DurableObjectState;
  
  constructor(state: DurableObjectState) {
    this.state = state;
  }
  
  async fetch(req: Request): Promise<Response> {
    let count = (await this.state.storage.get<number>('count')) ?? 0;
    count++;
    await this.state.storage.put('count', count);
    return Response.json({ count });
  }
}

// Worker
export default {
  async fetch(req: Request, env: Env) {
    const url = new URL(req.url);
    const name = url.searchParams.get('room') ?? 'default';
    const id = env.COUNTER.idFromName(name);
    const stub = env.COUNTER.get(id);
    return stub.fetch(req);
  },
};

→ Stateful — chat room, game session, rate limit.

R2 (S3-compatible storage)

const obj = await env.BUCKET.get('photo.jpg');
if (obj) return new Response(obj.body, { headers: { 'Content-Type': obj.httpMetadata?.contentType ?? '' } });

await env.BUCKET.put('upload.jpg', file, {
  httpMetadata: { contentType: 'image/jpeg' },
});

await env.BUCKET.delete('old.jpg');

→ S3-compat + free egress.

Cron triggers

# wrangler.toml
[triggers]
crons = ["0 9 * * *"]  # 매일 9시
export default {
  async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext) {
    await runDailyTask(env);
  },
  
  async fetch(req: Request, env: Env) { ... },
};

Queues (Cloudflare)

// Producer
await env.QUEUE.send({ orderId: '...', userId: '...' });

// Consumer
export default {
  async queue(batch: MessageBatch, env: Env) {
    for (const msg of batch.messages) {
      await processOrder(msg.body);
      msg.ack();
    }
  },
};

→ Decouple.

Limits (대략)

Cloudflare Workers:
- CPU: 30s (paid) / 10ms (free) per request
- Memory: 128 MB
- Subrequests: 1000
- Bundle: 10 MB
- Compute units / month: $5 = 10M+

Vercel Edge:
- CPU: 30s
- Memory: 128 MB
- Bundle: 1 MB

Deno Deploy:
- CPU: 50ms (per request)
- Memory: 512 MB

→ Long-running task = 다른 (Lambda / VM).

Edge 의 함정

1. CPU limit (10ms free) — 큰 work X.
2. Bundle size — Node module 일부 X.
3. Cold start — 거의 0 (V8 isolate).
4. Connection pool 어려움 (no persistent state).
5. 일부 Node API X (fs, child_process).

→ HTTP / KV / D1 만 사용.

Use cases (적합)

- API gateway (auth, rate limit, route)
- A/B test, geo redirect
- Image / response transformation
- Analytics ingestion
- Search index 호출
- Cache layer
- Webhook receiver
- Static site SSR

Use cases (안 적합)

- 큰 ML inference
- Long task (1 min+)
- Persistent connection (DB pool)
- File system 의존
- Large dependencies (Node-specific)

Multi-region database

Edge function 가 사용자 가까이.
DB 가 single region = 큰 latency.

해결:
- Read replica per region
- Hyperdrive (CF cache)
- Turso embedded replica
- 분산 DB (Spanner, Yugabyte)

Auth at edge

import { jwt } from 'hono/jwt';

app.use('/api/*', jwt({ secret: env.JWT_SECRET }));

// 또는 직접
async function verifyJwt(token: string, secret: string) {
  const [header, payload, signature] = token.split('.');
  // JWT verify (jose 같은 lib)
  return JSON.parse(atob(payload));
}

Static + Edge function

Vercel / Cloudflare Pages:
- Static assets — CDN
- API routes — edge function

→ Most modern stack.

Streaming

export default {
  async fetch() {
    const { readable, writable } = new TransformStream();
    const writer = writable.getWriter();
    
    (async () => {
      for (let i = 0; i < 5; i++) {
        await writer.write(new TextEncoder().encode(`chunk ${i}\n`));
        await new Promise(r => setTimeout(r, 1000));
      }
      writer.close();
    })();
    
    return new Response(readable);
  },
};

→ SSE / streaming response.

Test (local)

wrangler dev    # local + miniflare (Cloudflare emulator)
vercel dev
deno run --watch src/index.ts

Deploy

wrangler deploy --env production
vercel --prod
deployctl deploy --prod

Cost

Cloudflare Workers:
Free: 100K req/day
Paid: $5/month + $0.50 per million

Vercel:
Hobby: free
Pro: $20/month + execution time

→ 가장 cheap edge.

Comparison

Cloudflare:
+ 가장 빠름 (V8 isolate)
+ KV / D1 / R2 통합
+ Free tier 강
- Node API 제한

Vercel:
+ Next.js 통합 (best)
+ Frontend / API 통합
- 비싸 (큰 traffic)

Deno Deploy:
+ Deno native
+ Web Standard
- Smaller ecosystem

Fastly Compute@Edge:
+ Wasm 지원
+ 큰 enterprise

🤔 의사결정 기준

상황 추천
빠른 API + 글로벌 Cloudflare Workers
Next.js Vercel Edge
Deno project Deno Deploy
Wasm Fastly / CF Workers
Long task Lambda / VM
Big data Container / VM

안티패턴

  • Edge 안 long task: timeout.
  • Big bundle (큰 dep): limit.
  • Node-specific (fs, net): 깨짐.
  • DB persistent connection: HTTP driver.
  • Edge 가 모든 답: 가까운 user 가 critical 시만.
  • State in memory: cold isolate 에 잃음. KV / DO.

🤖 LLM 활용 힌트

  • Cloudflare Workers + D1 + KV = 가장 강.
  • Vercel Edge + Next.js = best DX.
  • Web Standard API only.
  • Cold start 거의 0.

🔗 관련 문서