cli icon indicating copy to clipboard operation
cli copied to clipboard

Edge runtime container lookup fails due to non-DNS-compliant container names

Open adapt0 opened this issue 5 months ago • 2 comments

Overview

With a Supabase local dev setup, Edge functions are unable to resolve container names, such as those provided by the SUPABASE_DB_URL environment variable. As CLI's generated container hostnames currently contain underscores, which Deno's strict resolver rejects due to non-compliance with RFC 1123 (only letters, numbers, and hyphens).

To Reproduce

  1. mkdir cloud && cd cloud
  2. supabase init
  3. supabase functions new hello
  4. Modify supabase/config.toml
    Under [functions.hello], set verify_jwt = false
  5. supabase start

Replace contents of supabase/functions/hello/index.ts with:

import postgres from 'npm:postgres'

const connectionString = Deno.env.get('SUPABASE_DB_URL')!

Deno.serve(async (_req) => {
  const output = [connectionString]

  try {
    const sql = postgres(connectionString, { prepare: false })
    output.push(`select 1 = ${JSON.stringify(await sql`select 1`)}`)
  } catch (e) {
    output.push(`sql error! - ${e}`)
    if (e instanceof Error && e.stack) output.push(e.stack)
  }

  return new Response(output.join('\n'))
})

Based on Supabase tutorial & Drizzle tutorial.

Expected behavior

postgresql://postgres:postgres@supabase_db_cloud:5432/postgres
select 1 = [{"?column?":1}]

Current behavior

postgresql://postgres:postgres@supabase_db_cloud:5432/postgres
sql error! - Error: getaddrinfo ENOTFOUND supabase_db_cloud
Error: getaddrinfo ENOTFOUND supabase_db_cloud
    at __node_internal_captureLargerStackTrace (ext:deno_node/internal/errors.ts:93:9)
    at __node_internal_ (ext:deno_node/internal/errors.ts:246:10)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:37:26)
    at ext:deno_node/internal_binding/cares_wrap.ts:78:9
    at eventLoopTick (ext:core/01_core.js:207:9)
    at cachedError (file:///var/tmp/sb-compile-edge-runtime/node_modules/localhost/postgres/3.4.7/src/query.js:170:23)
    at new Query (file:///var/tmp/sb-compile-edge-runtime/node_modules/localhost/postgres/3.4.7/src/query.js:36:24)
    at sql (file:///var/tmp/sb-compile-edge-runtime/node_modules/localhost/postgres/3.4.7/src/index.js:112:11)
    at Object.handler (file:///Users/adapt/tmp/repro/cloud/supabase/functions/hello/index.ts:12:55)

System information

  • OS: MacOS 15.6
  • CLI: 2.34.3
  • Docker: 4.44.2 (202017)
  • Services:
   SERVICE IMAGE          | LOCAL                  | LINKED
  ------------------------|------------------------|--------
   supabase/postgres      | 17.4.1.072             | -
   supabase/gotrue        | v2.178.0               | -
   postgrest/postgrest    | v13.0.4                | -
   supabase/realtime      | v2.41.23               | -
   supabase/storage-api   | v1.26.3                | -
   supabase/edge-runtime  | v1.68.3                | -
   supabase/studio        | 2025.08.04-sha-6e99ca6 | -
   supabase/postgres-meta | v0.91.5                | -
   supabase/logflare      | 1.18.3                 | -
   supabase/supavisor     | 2.6.1                  | -

Container names generated as part of a supabase start

NAMES
supabase_studio_cloud
supabase_pg_meta_cloud
supabase_edge_runtime_cloud
supabase_storage_cloud
supabase_rest_cloud
supabase_realtime_cloud
supabase_inbucket_cloud
supabase_auth_cloud
supabase_kong_cloud
supabase_vector_cloud
supabase_analytics_cloud
supabase_db_cloud

Other observations

Using db as the hostname works

postgresql://postgres:postgres@db:5432/postgres
select 1 = [{"?column?":1}]

Pinging from within the container is ok

docker exec -it supabase_edge_runtime_cloud /bin/sh -c 'apt update && apt install iputils-ping'

docker exec -it supabase_edge_runtime_cloud ping -c 1 supabase_db_cloud
PING supabase_db_cloud (172.20.0.2) 56(84) bytes of data.
64 bytes from supabase_db_cloud.supabase_network_cloud (172.20.0.2): icmp_seq=1 ttl=64 time=0.054 ms

Rolling up the sleeves

docker run --network supabase_network_cloud --name test-test -dt debian
docker run --network supabase_network_cloud --name test_test -dt debian

Update supabase/functions/hello/index.ts:

import { lookup } from "node:dns/promises"

const doLookup = async (host: string) => {
    try {
        return `lookup("${host}") ${(await lookup(host)).address}`
    } catch (e) {
        return `lookup("${host}") ${e}`
    }
}

Deno.serve(async (_req) => {
  const output = [
    await doLookup(URL.parse(Deno.env.get('SUPABASE_DB_URL')!)?.hostname!),
    await doLookup('db'),
    await doLookup('test_test'),
    await doLookup('test-test'),
    await doLookup('fail'),
  ]
  return new Response(output.join('\n'))
})

Outputs:

lookup("supabase_db_cloud") Error: getaddrinfo ENOTFOUND supabase_db_cloud
lookup("db") 172.20.0.2
lookup("test_test") Error: getaddrinfo ENOTFOUND test_test
lookup("test-test") 172.20.0.14
lookup("fail") Error: getaddrinfo ENOTFOUND fail

i.e., can resolve hostnames complying with RFC 1123

Workaround

Rewrite the hostname in the url supabase_db_cloud -> db

const connectionString = (() => {
  const url = URL.parse(Deno.env.get('SUPABASE_DB_URL')!)!
  url.hostname = url.hostname.split('_')[1]
  return url.href
})();

Soap box

While technically this is more of a compatibility between Docker's free for all container naming, ping be lenient on what it'll resolve, and Deno's strict/compliant resolver.

I feel there is a large value in addressing this in Supabase CLI.

Proposed solution

Use RFC 1123 compliant container names as part of supabase start

This would resolve the initial SUPABASE_DB_URL issue, as well as likely other issues when resolving container hostnames from Edge functions.

i.e., supabase_db_cloud -> supabase-db-cloud

Keeping in mind that the project_id in config.toml will need to be sanitized too.

adapt0 avatar Aug 17 '25 09:08 adapt0

We use container aliases for predictable hostname resolution https://github.com/supabase/cli/blob/e3d22ada3db8d89fc0790d97bcbd89b9f2f4db1d/internal/utils/config.go#L36

The only non-compliant alias is edge_runtime but since deno runs in it, there might not be an urgent need to change it.

sweatybridge avatar Nov 12 '25 13:11 sweatybridge

A supbase_ prefix and _{project} postfix is then used, which makes them all non-compliant:

https://github.com/supabase/cli/blob/e3d22ada3db8d89fc0790d97bcbd89b9f2f4db1d/internal/utils/config.go#L65-L68

https://github.com/supabase/cli/blob/e3d22ada3db8d89fc0790d97bcbd89b9f2f4db1d/internal/utils/config.go#L57-L59

Curiously lookup is fine if I run within a deno environment directly:

docker run -it --name db-test --network test denoland/deno repl
docker run -it --name db_test --network test denoland/deno repl
import { lookup } from "node:dns/promises"
await lookup('db_test')
# { address: "172.20.0.3", family: 4 }
await lookup('db-test')
# { address: "172.20.0.2", family: 4 }

Suggesting its something with edge functions?

adapt0 avatar Nov 17 '25 19:11 adapt0