15. Edge Functions

Alex needs to process a payment webhook and update an order — this requires custom server-side logic beyond SQL.

Edge Functions are serverless TypeScript/JavaScript functions that run on Eurobase's EU-sovereign infrastructure. They let you write custom server-side logic — payment processing, external API integrations, data transformations — without managing any servers.

EU Sovereign: Edge Functions run on Scaleway infrastructure in France. Unlike other platforms that route through US-hosted runtimes, your code and secrets never leave the EU.

Server-side logic in Eurobase: four kinds, when to pick which

Eurobase has four distinct surfaces for "code that runs on the server." The SDK shapes look similar in places, so it's worth getting the distinction clear before you start building. RPC functions and DB triggers are both PostgreSQL functions but with different invocation models; Cron jobs are scheduled wrappers around either an SQL statement or an RPC; Edge functions are a separate Deno runtime entirely.

 Cron JobRPC FunctionDB TriggerEdge Function
What it isA schedule that runs SQL or an RPC at a cron expressionA reusable Postgres function (SQL/PL-pgSQL) you call by nameA Postgres function bound to a row event on a tableServerless TS/JS in a Deno container
Where it runsInside Postgres (cron worker fires the SQL/RPC)Inside PostgresInside Postgres, in the row's transactionDeno container, outside the database
How it's invokedBy the cron schedule (no caller)eb.db.rpc('name') from the SDK, or from a cron jobAutomatically, when an INSERT / UPDATE / DELETE / TRUNCATE happens on the attached tableeb.functions.invoke('name') or HTTP
LanguageSQL (or pick an RPC)SQL or PL/pgSQLPL/pgSQL (return type trigger)TypeScript / JavaScript
TransactionalYes — its own transaction at run timeYes — runs in the caller's transactionYes — runs in the row operation's transaction (can roll it back by raising)No — separate process
Where to manage itCron & RPC → Scheduled JobsCron & RPC → FunctionsFunction: Cron & RPC → Functions (Returns: trigger). Attachment: Database → table → Triggers panelFunctions tab
Use case examplesDaily cleanup of expired sessions; weekly digest aggregation; archiving old rowsComputed leaderboard, multi-statement bulk update, an atomic check-and-decrement, complex aggregate the SDK can call by nameEnforcing a max-N-rows-per-user constraint on INSERT; auto-stamping updated_at; mirroring inserts into an audit tableStripe / Mollie webhook; sending email via TEM; calling an external image-processing API; OAuth callback handling
Pick whenYou want something to run on a schedule, regardless of user activityYour app needs to call a chunk of DB-only logic by name, atomicallyA row change must always be accompanied by side-effect SQL — and the side effect must succeed or fail with the row changeYou need the JS ecosystem, an external HTTP call, or anything Postgres can't reach from within the database

Mental model: Cron jobs are scheduled SQL; RPC is callable SQL; DB triggers are reactive SQL; edge functions are everything else. The first three all run inside Postgres and share its transactional model. Edge functions are a separate runtime that talks to the DB over the SDK like your app does.

One subtle gotcha: a function that RETURNS trigger is created in the same place as RPC functions, but it won't appear in the RPC list and can't be called via eb.db.rpc(). It only exists to be attached to a table by a trigger. The Functions list filters it out so the surfaces stay honest. To attach it: Database tab → pick the table → expand the Triggers panel.

Creating a Function

From the console, navigate to Functions tab and click + New Function. Give it a lowercase name with hyphens (e.g., process-order).

Or via CLI:

eurobase edge-functions deploy process-order --file functions/process-order.ts

Function Structure

Write TypeScript or JavaScript and export your handler with export default (or module.exports). The runner passes req (a Request) and ctx (context). Code is compiled on deploy — types are stripped, not checked.

Heads-up: third-party imports (import … from "https://…" or npm packages) are not supported yet — inline dependencies into the function file.

Reading the request (webhooks & APIs)

Your function receives the full incoming request, so it can act as a webhook receiver or small HTTP API:

  • Query stringnew URL(req.url).searchParams.get('token')
  • Custom headersreq.headers.get('X-Signature'), X-Api-Key, X-Webhook-Id, etc. are forwarded as sent.
  • Bodyawait req.json() / req.text(); Content-Type is preserved.

Withheld from your function so platform credentials don't leak: the auth that authenticates your call to Eurobase — the Authorization, apikey, Cookie headers and the ?apikey= query param — plus Eurobase's internal X-Eurobase-* / X-Project-* / X-Function-* / X-User-* headers. For end-user identity on a verify_jwt function, use ctx.user. Put a partner's auth token in any other custom header (e.g. X-Api-Key, X-Signature) or query param (e.g. ?token=).

TypeScript types (autocomplete + type-checking)

The full req and ctx shapes are shipped from the SDK as a types-only subpath. Import in your function source with a type-only import (bundlers elide it at build time):

import type { EdgeHandler } from '@eurobase/sdk/functions'

const handler: EdgeHandler = async (req, ctx) => {
  const { orderId } = (await req.json()) as { orderId: string }
  const rows = await ctx.db.sql<{ id: string; total: number }>(
    "SELECT id, total FROM orders WHERE id = $1",
    [orderId],
  )
  return Response.json(rows[0])
}

export default handler

Requires @eurobase/sdk@0.7.0 or later. The exported types (EdgeContext, EdgeHandler, EdgeUser, EdgeStorageUploadResult, EdgeSignedUrlResult, EdgeLogger) mirror the runtime ctx the runner passes to your handler, so autocomplete and type-checking cover every helper. Note: ctx.db.sql(...) resolves to the bare row array — assign directly with const rows = ..., not destructured with const { rows } = ....

Example handler

module.exports = async (req, ctx) => {
  // Parse the incoming request
  const { orderId } = await req.json();

  // Query the database (scoped to your project)
  // ctx.db.sql resolves to the rows array directly.
  const rows = await ctx.db.sql(
    "SELECT * FROM orders WHERE id = $1",
    [orderId]
  );
  const order = rows[0];

  // Read a secret from Vault
  const apiKey = await ctx.vault.get("PAYMENT_API_KEY");

  // Call an external API
  const payment = await fetch("https://api.mollie.com/v2/payments", {
    method: "POST",
    headers: { Authorization: `Bearer ${ apiKey }` },
    body: JSON.stringify({ amount: order.total })
  });

  // Return a response
  return new Response(JSON.stringify({ status: "ok" }), {
    status: 200,
    headers: { "Content-Type": "application/json" },
  });
};

Context API

PropertyDescription
ctx.db.sql(query, params)Execute SQL scoped to your project schema
ctx.vault.get(name)Read an encrypted secret from Vault
ctx.envPer-function environment variables
ctx.user.id / ctx.user.emailAuthenticated user (if JWT required)
ctx.log.info(msg) / .warn / .errorStructured logging (visible in Logs)

Invoking Functions

Functions are invoked via HTTP using your API key:

POST https://your-project.eurobase.app/v1/functions/process-order
Authorization: Bearer <user-jwt>
apikey: eb_pk_...

{"orderId": "abc-123"}

Or via the SDK:

const { data, error } = await eurobase.functions.invoke('process-order', {
  body: { orderId: 'abc-123' },
});

CLI Commands

# List edge functions
eurobase edge-functions list

# Deploy from local file
eurobase edge-functions deploy process-order -f functions/process-order.ts

# View execution logs
eurobase edge-functions logs process-order

# Delete a function
eurobase edge-functions delete process-order

Plan Limits

LimitFreePro
Functions per project325
Execution timeout10 seconds60 seconds
Memory per execution64 MB256 MB

Use Cases

  • Payment webhooks — Process Mollie callbacks, update order status
  • External integrations — Sync data to/from other EU SaaS
  • Custom auth logic — Post-signup hooks, role assignment
  • Data transformation — Parse CSVs, enrich records, generate reports
  • Notifications — Send emails, push notifications on events