Edge Functions for Website (Deno Deploy)

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Edge Functions Development for Websites (Deno Deploy)

Deno Deploy is a distributed runtime platform running JavaScript and TypeScript on V8 Isolates in 35+ regions with no cold start. Unlike Lambda or Cloud Functions, code executes in milliseconds from the user because it doesn't spin up a container — the isolate is already ready.

Typical tasks for Edge Functions on websites: A/B testing at CDN level, personalization by geolocation, authorization middleware, request proxying with transformation, dynamic OG image generation.

How Deno Deploy Works

Each function is an ES module with a Deno.serve handler. The platform doesn't support the file system (except bundle), no setTimeout with long delays, no background execution after response (except waitUntil in some cases).

// entry.ts
Deno.serve(async (req: Request) => {
  const url = new URL(req.url);

  if (url.pathname === '/api/geo') {
    const country = req.headers.get('x-deno-country') ?? 'unknown';
    const region = req.headers.get('x-deno-region') ?? 'unknown';

    return Response.json({ country, region });
  }

  return new Response('Not Found', { status: 404 });
});

Deployment via CLI:

deno install -A jsr:@deno/deployctl
deployctl deploy --project=my-site entry.ts

Middleware for Authorization

Often need to verify JWT or session token before the request reaches the origin. On Edge, this is done without a roundtrip to the backend:

import { create, verify, getNumericDate } from 'https://deno.land/x/[email protected]/mod.ts';

const JWT_SECRET = Deno.env.get('JWT_SECRET')!;

async function getKey(secret: string): Promise<CryptoKey> {
  const enc = new TextEncoder();
  return await crypto.subtle.importKey(
    'raw',
    enc.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign', 'verify']
  );
}

Deno.serve(async (req: Request) => {
  const url = new URL(req.url);

  // Public routes
  if (url.pathname.startsWith('/public') || url.pathname === '/') {
    return await fetch(req); // proxy to origin
  }

  const authHeader = req.headers.get('Authorization');
  if (!authHeader?.startsWith('Bearer ')) {
    return new Response('Unauthorized', { status: 401 });
  }

  const token = authHeader.slice(7);

  try {
    const key = await getKey(JWT_SECRET);
    const payload = await verify(token, key);

    // Add user data to header for origin
    const modifiedReq = new Request(req, {
      headers: {
        ...Object.fromEntries(req.headers),
        'x-user-id': String(payload.sub),
        'x-user-role': String(payload.role ?? 'user'),
      },
    });

    return await fetch(modifiedReq);
  } catch {
    return new Response('Invalid token', { status: 401 });
  }
});

Geolocation Personalization

Deno Deploy passes geo data via headers. Useful for language redirects, regional pricing, country blocking:

const COUNTRY_REDIRECTS: Record<string, string> = {
  RU: 'https://ru.example.com',
  BY: 'https://ru.example.com',
  DE: 'https://de.example.com',
  FR: 'https://fr.example.com',
};

Deno.serve((req: Request) => {
  const url = new URL(req.url);

  if (url.pathname !== '/') {
    return fetch(req);
  }

  const cookies = req.headers.get('Cookie') ?? '';
  if (cookies.includes('locale-selected=1')) {
    return fetch(req);
  }

  const country = req.headers.get('x-deno-country');
  const target = country ? COUNTRY_REDIRECTS[country] : null;

  if (target) {
    return new Response(null, {
      status: 302,
      headers: {
        Location: target,
        'Set-Cookie': 'locale-selected=1; Path=/; Max-Age=86400; SameSite=Lax',
      },
    });
  }

  return fetch(req);
});

OG Image Generation on Edge

Satori—a library for rendering JSX to SVG—works in Deno Deploy. Allows generating unique preview images for each page without prebuild:

import satori from 'npm:[email protected]';
import { Resvg } from 'npm:@resvg/[email protected]';

Deno.serve(async (req: Request) => {
  const url = new URL(req.url);
  if (!url.pathname.startsWith('/og')) return new Response('Not Found', { status: 404 });

  const title = url.searchParams.get('title') ?? 'My Site';
  const description = url.searchParams.get('desc') ?? '';

  const fontResponse = await fetch('https://your-cdn.com/fonts/Inter-Bold.ttf');
  const fontBuffer = await fontResponse.arrayBuffer();

  const svg = await satori(
    {
      type: 'div',
      props: {
        style: {
          display: 'flex',
          flexDirection: 'column',
          width: '100%',
          height: '100%',
          background: '#0f172a',
          padding: '60px',
          fontFamily: 'Inter',
        },
        children: [
          {
            type: 'h1',
            props: {
              style: { color: '#f8fafc', fontSize: 56, margin: 0, lineHeight: 1.2 },
              children: title,
            },
          },
          {
            type: 'p',
            props: {
              style: { color: '#94a3b8', fontSize: 28, marginTop: 24 },
              children: description,
            },
          },
        ],
      },
    },
    {
      width: 1200,
      height: 630,
      fonts: [{ name: 'Inter', data: fontBuffer, weight: 700, style: 'normal' }],
    }
  );

  const resvg = new Resvg(svg);
  const png = resvg.render().asPng();

  return new Response(png, {
    headers: {
      'Content-Type': 'image/png',
      'Cache-Control': 'public, max-age=86400, stale-while-revalidate=604800',
    },
  });
});

Caching with Deno KV

Deno KV is a built-in key-value store with global replication. Used for caching, counters, rate limiting:

const kv = await Deno.openKv();

Deno.serve(async (req: Request) => {
  const url = new URL(req.url);
  const cacheKey = ['cache', url.pathname + url.search];

  const cached = await kv.get<string>(cacheKey);
  if (cached.value) {
    return new Response(cached.value, {
      headers: {
        'Content-Type': 'application/json',
        'X-Cache': 'HIT',
      },
    });
  }

  const response = await fetch(`https://api.example.com${url.pathname}`);
  const data = await response.text();

  await kv.set(cacheKey, data, { expireIn: 5 * 60 * 1000 });

  return new Response(data, {
    headers: {
      'Content-Type': 'application/json',
      'X-Cache': 'MISS',
    },
  });
});

Rate Limiting on Edge

const kv = await Deno.openKv();

async function rateLimit(ip: string, limit = 60, windowSeconds = 60): Promise<boolean> {
  const key = ['ratelimit', ip, Math.floor(Date.now() / (windowSeconds * 1000))];
  const entry = await kv.get<number>(key);
  const count = (entry.value ?? 0) + 1;

  if (count > limit) return false;

  await kv.set(key, count, { expireIn: windowSeconds * 1000 });
  return true;
}

Deno.serve(async (req: Request) => {
  const ip = req.headers.get('x-forwarded-for') ?? '0.0.0.0';
  const allowed = await rateLimit(ip);

  if (!allowed) {
    return new Response('Too Many Requests', {
      status: 429,
      headers: { 'Retry-After': '60' },
    });
  }

  return fetch(req);
});

Timeframe

Simple Edge Function (redirect, geolocation, basic middleware) — 1–2 days including testing and deployment. Middleware with JWT verification and proxying — 2–3 days. OG image generation with Deno KV caching — 3–5 days. Full Edge Layer with rate limiting, A/B testing, and analytics — 1–2 weeks.