Skip to main content
This document is the single reference for testing Supabase Edge Functions and the Functions API from your IDE and local environment. It covers local stack workflow, debugging with breakpoints, Deno unit tests, integration tests against local functions, and troubleshooting. See also: TESTING_SETUP_AND_RUN.md (all test types), EDGE_FUNCTIONS.md (function reference and deployment). Verification results: EDGE_AND_API_VERIFICATION_RESULTS.md.

Prerequisites

  • Supabase CLI — Install globally or use npx supabase from the project root. See Install the Supabase CLI.
  • Docker — Required for supabase start (local Postgres, Auth, etc.).
  • Deno (optional) — For running Edge Function unit tests (deno test). Install from deno.land if you want to run npm run test:functions locally.

Full local stack

  1. Start the local Supabase stack (Postgres, Auth, Realtime, Storage, etc.):
    Or: npm run supabase:start (if you use the npm script). Get the API URL and anon key with:
  2. Serve Edge Functions with hot-reload:
    This runs the hardened wrapper scripts/setup/serve-functions.sh (not bare supabase functions serve). The wrapper is safe to run from any checkout — root or a git worktree — and fixes the two recurring multi-agent failure modes:
    • Worktree basename trap: the Supabase CLI names its Docker project after the working-directory basename, so a bare supabase functions serve from …/.claude/worktrees/<slug> targets a nonexistent <slug> stack and fails. The wrapper resolves the root checkout (via the git common-dir) and passes --workdir <root>, so every worktree shares the one canonical stack on :54321.
    • Edge-runtime name conflict: the CLI does not reap its supabase_edge_runtime_<project> container on an unclean exit, so the next serve dies with “container name is already in use”. The wrapper force-removes that one container first (it is recreated fresh every serve; the persistent db/kong/etc. stack is untouched). It also probes the gateway and reuses an already-running serve instead of starting a second one (SERVE_NO_REUSE=1 forces a fresh serve).
    ⚠️ Because the shared stack belongs to the root checkout, the wrapper serves root’s supabase/functions, not the functions you edited in a worktree. If you changed an edge function in a worktree, get it into root first (commit + check root out to your branch, or copy the changed supabase/functions/<fn> dirs into root) — the wrapper prints a loud warning when it detects this case. Omitting a function name serves all functions; hot-reload is on by default.
  3. Invoke locally:
    • From the app: Point VITE_SUPABASE_URL at http://localhost:54321 and use supabase.functions.invoke('my-func', { body }).
    • From terminal (cURL):
      Use the anon key from npx supabase status.

Local env for Edge/API

For local function and API testing, use a .env.local (or shell export) with:
  • VITE_SUPABASE_URL=http://localhost:54321
  • VITE_SUPABASE_PUBLISHABLE_KEY=<anon key from npx supabase status>
Get the anon key after running supabase start:
Use the anon key for client-style calls; use service_role only for tests that need elevated access (e.g. integration tests using the service role client).

Debugging with breakpoints

  1. Start functions in inspect mode:
    This runs supabase functions serve --inspect-mode brk. Execution pauses on the first line when a request hits a function.
  2. Attach Chrome DevTools:
    • Open Chrome and go to chrome://inspect.
    • Click Configure and add target 127.0.0.1:8083.
    • Under “Remote Target”, click Open dedicated DevTools for Node.
  3. Trigger a function (e.g. cURL or the app). Execution will pause so you can set breakpoints, step through code, and inspect variables.

Deno unit tests

Location: Tests are co-located with functions, e.g.:
  • supabase/functions/<name>/index.test.ts
  • supabase/functions/<name>/index_test.ts
Examples: generate-templated-pdf/index.test.ts, hr-encrypt-bank-account/index_test.ts. Environment when testing against local:
  • generate-templated-pdf and similar: Set VITE_SUPABASE_URL=http://localhost:54321 and VITE_SUPABASE_PUBLISHABLE_KEY=<anon from npx supabase status>.
  • hr-encrypt-bank-account: Set SUPABASE_URL=http://localhost:54321 (and optionally TEST_AUTH_TOKEN for authenticated tests).
Run from repo root:
This runs all Deno tests under supabase/functions. Ensure the local stack and supabase functions serve are running if tests call the HTTP endpoint. IDE: Use the Deno extension in VS Code/Cursor and the task “Run Edge Function (Deno) tests” to run the same command from the editor. If your workspace has no .vscode/tasks.json, copy or merge from docs/development/vscode-tasks-edge-functions.json into .vscode/tasks.json.

API Gateway parity (local vs production)

For prod-like local behavior, run supabase functions serve without --no-verify-jwt and send a valid Authorization: Bearer <token> header (anon key or user JWT). The default npm run supabase:functions:serve uses --no-verify-jwt for easier local iteration; use inspect or a separate serve command when testing JWT verification.

Logs

  • Local: Function stdout/stderr appear in the terminal where you ran supabase functions serve.
  • Production: Use the Supabase Dashboard (Edge Function logs) or the CLI. Use structured logging in code (e.g. logger.info with correlationId, no PHI) for easier filtering.

Integration tests against local

To run Vitest integration tests that invoke Edge Functions against your local stack:
  1. Set VITE_SUPABASE_URL=http://localhost:54321 and SUPABASE_SERVICE_ROLE_KEY (and VITE_SUPABASE_PUBLISHABLE_KEY if tests use anon client). Get keys from npx supabase status after supabase start.
  2. Run npm run supabase:functions:serve in a separate terminal.
  3. Run integration tests, e.g.:
    Or a subset, e.g.:
The test setup uses tests/setup.ts and tests such as tests/integration/fa/plaid-create-link-token.test.ts use VITE_SUPABASE_URL and supabase.functions.invoke. With the URL pointing at local and functions serve running, those tests hit your local functions.

Fast prod checks

  • Dashboard: Use the Test tab for each function in the Supabase Dashboard to try different headers, payloads, and JWTs.
  • cURL:

Troubleshooting checklist


See also