Working around the Edge Function secrets limit

Edge Functions projects are capped at 100 secrets (see Functions limits). If you’re managing credentials for many third-party services, you can hit this cap even though you haven’t done anything wrong — each supabase secrets set NAME=VALUE call uses one slot, regardless of how small the value is.

Supabase doesn’t raise this limit on a per-project basis today. The workaround below gets around it — though the per-secret size limit below still applies, so it isn’t a way around every constraint.

How to fix

  1. Group related credentials into a JSON object and store it under a single secret name:

    supabase secrets set API_KEYS='{"stripe":"sk_live_xxx","sendgrid":"SG.xxx","aws":"xxx"}'

    This counts as one secret against the 100 limit, no matter how many keys are nested inside it.

  2. Read it back in your function with Deno.env.get() and JSON.parse:

    const raw = Deno.env.get('API_KEYS')
    if (!raw) {
    throw new Error('Missing API_KEYS secret')
    }
    const keys = JSON.parse(raw)
    const stripeKey = keys.stripe
  3. Confirm it was set with supabase secrets list.

This is the same pattern Supabase’s own default secrets use — SUPABASE_PUBLISHABLE_KEYS and SUPABASE_SECRET_KEYS are themselves JSON dictionaries parsed the same way (see Environment variables).

Things to watch for

  • No partial updates. Setting a new value replaces the whole secret, so updating one key means re-setting the entire JSON blob. Build the JSON with a script or jq rather than hand-typing it — a single typo breaks every key in the group.
  • Quoting on the command line gets messy fast, especially outside bash/zsh (e.g. Windows shells don’t handle single-quote literals the same way). If that happens, load the secret from a file instead — the value isn’t parsed by the shell, which sidesteps the escaping problem:
    supabase secrets set --env-file .env
  • Secrets are capped at 48 KiB (24,576 characters) (Functions limits). Group logically — for example, one secret per third-party integration — rather than merging everything into a single blob. Typical API keys (tens to a couple hundred characters) leave plenty of headroom; long-lived tokens, JWTs, or certificates can approach the size cap with only a handful of entries.

When this isn’t the right fit

Consider Supabase Vault when your values vary by row, such as secrets tied to individual users or organizations. Vault stores encrypted secrets in Postgres, and the 100-secret limit doesn’t apply.

Reading a Vault secret from an Edge Function costs a database round-trip, either supabase.rpc() against a security definer function or a service-role query. That adds latency.

For a flat list of project-wide credentials, grouping them into a single JSON secret avoids the round-trip.

Additional resources