{ "module": "supabase", "version": "1", "capabilities": [ "container-runtime" ], "listens": [ { "name": "api", "port": 8000, "protocol": "tcp", "from": "mesh", "why": "the Kong gateway: the REST, auth, storage, realtime, functions and GraphQL APIs under their /\u2026/v1 paths, and Studio at / behind the dashboard password. The one surface people and apps use, reached through the route" }, { "name": "pooler-session", "port": 5432, "protocol": "tcp", "from": "mesh", "why": "Supavisor's session-mode Postgres port, for clients that connect to the database directly as ." }, { "name": "pooler-transaction", "port": 6543, "protocol": "tcp", "from": "mesh", "why": "Supavisor's transaction-mode Postgres port" } ], "requires": [ "route" ], "own-secrets": { "postgres": "${dir:state}/postgres.secret", "jwt": "${dir:state}/jwt.secret", "anon-key": "${dir:state}/anon-key.secret", "service-role-key": "${dir:state}/service-role-key.secret", "dashboard-user": "${dir:state}/dashboard-user.secret", "dashboard": "${dir:state}/dashboard.secret", "logflare": { "path": "${dir:state}/logflare.secret", "taken": "at-start" }, "pooler-vault": "${dir:state}/pooler-vault.secret", "key-base-a": "${dir:state}/key-base-a.secret", "key-base-b": "${dir:state}/key-base-b.secret", "openai": { "path": "${dir:state}/openai.secret", "issued-by": "outside" } }, "contributes": { "route": { "label": "supabase", "endpoint": "api" } }, "binds": { "route": "${dir:state}/route.json" }, "data": { "own": [ { "id": "db", "path": "${dir:db-data}", "class": "valuable", "backup": { "dump": "docker exec supabase-db pg_dumpall -h 127.0.0.1 -U supabase_admin > ${dir:dumps}/all.sql.partial && mv ${dir:dumps}/all.sql.partial ${dir:dumps}/all.sql", "into": "dumps" }, "why": "every table; copied by pg_dumpall inside the database's container (local connections are trusted there), since a running store's files are not a consistent copy" }, { "id": "dumps", "path": "${dir:dumps}", "class": "rebuildable", "why": "last night's dump of the database, made again every night" }, { "id": "storage", "path": "${dir:storage}", "class": "valuable", "why": "uploaded objects" }, { "id": "functions", "path": "${dir:functions}", "class": "valuable", "why": "the edge functions' code" }, { "id": "db-config", "path": "${dir:db-config}", "class": "rebuildable", "why": "the database's configuration, seeded again" } ] }, "config": { "pooler": { "type": "object", "description": "The connection pooler's settings, laid over the file's: its tenant, pool size and the most client connections it takes.", "trusted": true, "default": { "tenant": "default", "pool-size": 20, "max-client-connections": 100 } } }, "resources": [ { "id": "state", "type": "directory", "mode": "0700", "place": "." }, { "id": "db-init", "type": "directory", "path": "${dir:state}/db-init", "mode": "0755" }, { "id": "functions-main-dir", "type": "directory", "path": "${dir:state}/functions-main", "mode": "0755" }, { "id": "db-data", "type": "directory", "mode": "0700", "owner": "105:106" }, { "id": "dumps", "type": "directory", "path": "${dir:state}/dumps", "mode": "0700" }, { "id": "db-config", "type": "directory", "mode": "0755", "owner": "105:106" }, { "id": "storage", "type": "directory", "mode": "0755" }, { "id": "functions", "type": "directory", "mode": "0755" }, { "id": "settings", "type": "file", "path": "${dir:state}/settings.json", "mode": "0644", "merge": "json", "takes-config": ["pooler"], "template": "files/settings.json" }, { "id": "kong-conf", "type": "file", "path": "${dir:state}/kong.yml", "mode": "0600", "owner": "100:65533", "template": "files/kong.yml" }, { "id": "auth-conf", "type": "file", "path": "${dir:state}/gotrue.env", "mode": "0600", "owner": "1000:1000", "template": "files/gotrue.env" }, { "id": "rest-conf", "type": "file", "path": "${dir:state}/postgrest.conf", "mode": "0600", "owner": "1000:1000", "template": "files/postgrest.conf" }, { "id": "vector-conf", "type": "file", "path": "${dir:state}/vector.yml", "mode": "0600", "template": "files/vector.yml" }, { "id": "pooler-conf", "type": "file", "path": "${dir:state}/pooler.exs", "mode": "0644", "template": "files/pooler.exs" }, { "id": "db-init-roles", "type": "file", "path": "${dir:state}/db-init/roles.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/roles.sql" }, { "id": "db-init-jwt", "type": "file", "path": "${dir:state}/db-init/jwt.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/jwt.sql" }, { "id": "db-init-realtime", "type": "file", "path": "${dir:state}/db-init/realtime.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/realtime.sql" }, { "id": "db-init-supabase", "type": "file", "path": "${dir:state}/db-init/supabase.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/supabase.sql" }, { "id": "db-init-logs", "type": "file", "path": "${dir:state}/db-init/logs.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/logs.sql" }, { "id": "db-init-pooler", "type": "file", "path": "${dir:state}/db-init/pooler.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/pooler.sql" }, { "id": "db-init-webhooks", "type": "file", "path": "${dir:state}/db-init/webhooks.sql", "mode": "0600", "owner": "105:106", "template": "files/db-init/webhooks.sql" }, { "id": "functions-main", "type": "file", "path": "${dir:state}/functions-main/index.ts", "mode": "0644", "template": "files/functions-main/index.ts" }, { "id": "realtime-env", "type": "file", "path": "${dir:state}/realtime-env.env", "mode": "0600", "template": "files/realtime-env.env" }, { "id": "storage-env", "type": "file", "path": "${dir:state}/storage-env.env", "mode": "0600", "template": "files/storage-env.env" }, { "id": "meta-env", "type": "file", "path": "${dir:state}/meta-env.env", "mode": "0600", "template": "files/meta-env.env" }, { "id": "functions-env", "type": "file", "path": "${dir:state}/functions-env.env", "mode": "0600", "template": "files/functions-env.env" }, { "id": "analytics-env", "type": "file", "path": "${dir:state}/analytics-env.env", "mode": "0600", "template": "files/analytics-env.env" }, { "id": "analytics-start", "type": "file", "path": "${dir:state}/analytics-start.sh", "mode": "0644", "template": "files/analytics-start.sh" }, { "id": "analytics-reconcile", "type": "file", "path": "${dir:state}/analytics-reconcile.exs", "mode": "0644", "template": "files/analytics-reconcile.exs" }, { "id": "studio-env", "type": "file", "path": "${dir:state}/studio-env.env", "mode": "0600", "template": "files/studio-env.env" }, { "id": "pooler-env", "type": "file", "path": "${dir:state}/pooler-env.env", "mode": "0600", "template": "files/pooler-env.env" }, { "id": "net", "type": "network", "name": "supabase" }, { "id": "vector", "type": "container", "name": "supabase-vector", "image": "timberio/vector@sha256:4bc04aca94a44f04b427a490f346e7397ef7ce61fe589d718f744f7d92cb5c80", "network": "supabase", "args": [ "--config", "/etc/vector/vector.yml" ], "volumes": [ "${dir:state}/vector.yml:/etc/vector/vector.yml:ro", "/var/run/docker.sock:/var/run/docker.sock:ro" ], "restart-on": [ "vector-conf" ] }, { "id": "db-config-seed", "type": "container", "name": "supabase-db-config-seed", "image": "supabase/postgres@sha256:ee29d0aaff03d0e12c7aa63437cba25f24246872f0ed3f82a9fd13184d780777", "network": "supabase", "run-once": true, "args": [ "sh", "-c", "cp -rn /etc/postgresql-custom/. /seed/ && chown -R postgres:postgres /seed" ], "volumes": [ "${dir:db-config}:/seed" ] }, { "id": "db", "type": "container", "name": "supabase-db", "image": "supabase/postgres@sha256:ee29d0aaff03d0e12c7aa63437cba25f24246872f0ed3f82a9fd13184d780777", "health": { "kind": "runtime" }, "network": "supabase", "args": [ "postgres", "-c", "config_file=/etc/postgresql/postgresql.conf", "-c", "log_min_messages=fatal" ], "env": { "POSTGRES_HOST": "/var/run/postgresql", "PGPORT": "5432", "POSTGRES_PORT": "5432", "PGDATABASE": "postgres", "POSTGRES_DB": "postgres", "POSTGRES_PASSWORD_FILE": "/run/secrets/postgres" }, "volumes": [ "${dir:state}/postgres.secret:/run/secrets/postgres:ro", "${dir:state}/db-init/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:ro", "${dir:state}/db-init/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:ro", "${dir:state}/db-init/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:ro", "${dir:state}/db-init/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:ro", "${dir:state}/db-init/supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:ro", "${dir:state}/db-init/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:ro", "${dir:state}/db-init/pooler.sql:/docker-entrypoint-initdb.d/migrations/99-pooler.sql:ro", "${dir:db-data}:/var/lib/postgresql/data", "${dir:db-config}:/etc/postgresql-custom" ] }, { "id": "db-ready", "type": "container", "name": "supabase-db-ready", "image": "supabase/postgres@sha256:ee29d0aaff03d0e12c7aa63437cba25f24246872f0ed3f82a9fd13184d780777", "network": "supabase", "run-once": true, "args": [ "sh", "-c", "for i in $(seq 150); do pg_isready -h supabase-db -p 5432 -U postgres && exit 0; sleep 2; done; echo 'the database did not come up' >&2; exit 1" ] }, { "id": "analytics", "type": "container", "name": "supabase-analytics", "image": "supabase/logflare@sha256:e693c787ffe1ae17b6e4e920a3cdd212416d3e1f97e1bd7cb5b67de0abbb0264", "network": "supabase", "env-file": [ "${dir:state}/analytics-env.env" ], "volumes": [ "${dir:state}/analytics-start.sh:/run/logflare/start.sh:ro", "${dir:state}/vector.yml:/run/logflare/vector.yml:ro", "${dir:state}/analytics-reconcile.exs:/run/logflare/reconcile.exs:ro" ], "args": [ "sh", "/run/logflare/start.sh" ], "restart-on": [ "analytics-env", "analytics-start", "analytics-reconcile", "vector-conf" ], "secrets-in-environment": "Logflare reads its database password and API key from the environment only. The API key is never in a URL the mesh writes: logflare prints a failed request's URL, so vector sends the key in the x-api-key header, and the start script refuses to start logflare while vector.yml says otherwise" }, { "id": "analytics-ready", "type": "container", "name": "supabase-analytics-ready", "image": "supabase/logflare@sha256:e693c787ffe1ae17b6e4e920a3cdd212416d3e1f97e1bd7cb5b67de0abbb0264", "network": "supabase", "run-once": true, "args": [ "sh", "-c", "for i in $(seq 150); do curl -fsS -o /dev/null http://supabase-analytics:4000/health && exit 0; sleep 2; done; echo 'analytics did not come up' >&2; exit 1" ] }, { "id": "kong", "type": "container", "name": "supabase-kong", "image": "kong@sha256:1b53405d8680a09d6f44494b7990bf7da2ea43f84a258c59717d4539abf09f6d", "health": { "kind": "runtime" }, "network": "supabase", "ports": [ "8000" ], "env": { "KONG_DATABASE": "off", "KONG_DECLARATIVE_CONFIG": "/home/kong/kong.yml", "KONG_DNS_ORDER": "LAST,A,CNAME", "KONG_PLUGINS": "request-transformer,cors,key-auth,acl,basic-auth", "KONG_NGINX_PROXY_PROXY_BUFFER_SIZE": "160k", "KONG_NGINX_PROXY_PROXY_BUFFERS": "64 160k" }, "volumes": [ "${dir:state}/kong.yml:/home/kong/kong.yml:ro" ], "restart-on": [ "kong-conf" ] }, { "id": "auth", "type": "container", "name": "supabase-auth", "image": "supabase/gotrue@sha256:f8b871f46f3f9c5306af00d2fb856fb5479db730bb6d4fd2757b2da8abe953f9", "network": "supabase", "args": [ "auth", "-c", "/etc/gotrue/gotrue.env" ], "volumes": [ "${dir:state}/gotrue.env:/etc/gotrue/gotrue.env:ro" ], "restart-on": [ "auth-conf" ] }, { "id": "rest", "type": "container", "name": "supabase-rest", "image": "postgrest/postgrest@sha256:2cf1efd2c9c2e7606610c113cc73e936d8ce9ba089271cb9cbf11aa564bc30c7", "network": "supabase", "args": [ "postgrest", "/etc/postgrest/postgrest.conf" ], "volumes": [ "${dir:state}/postgrest.conf:/etc/postgrest/postgrest.conf:ro" ], "restart-on": [ "rest-conf" ] }, { "id": "realtime", "type": "container", "name": "realtime-dev.supabase-realtime", "image": "supabase/realtime@sha256:104fe2e4e09a7c81eebe0c39e3a9b9dca4684f55470ca01cb3c080d1d56453a1", "network": "supabase", "env-file": [ "${dir:state}/realtime-env.env" ], "secrets-in-environment": "Supabase Realtime (Elixir release) reads DB_PASSWORD, API_JWT_SECRET and SECRET_KEY_BASE from its environment only; no file or _FILE form" }, { "id": "imgproxy", "type": "container", "name": "supabase-imgproxy", "image": "darthsim/imgproxy@sha256:0facd355d50f3be665ebe674486f2b2e9cdaebd3f74404acd9b7fece2f661435", "network": "supabase", "env": { "IMGPROXY_BIND": ":5001", "IMGPROXY_LOCAL_FILESYSTEM_ROOT": "/", "IMGPROXY_USE_ETAG": "true", "IMGPROXY_ENABLE_WEBP_DETECTION": "true" }, "volumes": [ "${dir:storage}:/var/lib/storage" ] }, { "id": "storage-api", "type": "container", "name": "supabase-storage", "image": "supabase/storage-api@sha256:1e85dad48e8b3e85890a555e5114dc7ee48c2e8be4cfd97dd4e3564b4f104fcd", "network": "supabase", "volumes": [ "${dir:storage}:/var/lib/storage" ], "env-file": [ "${dir:state}/storage-env.env" ], "secrets-in-environment": "Supabase Storage reads its keys and DATABASE_URL from the environment only" }, { "id": "meta", "type": "container", "name": "supabase-meta", "image": "supabase/postgres-meta@sha256:d0a96973e9f1b6303f7500421a459af3d7273b3f9f1db38610899f9f573da7c7", "health": { "kind": "runtime" }, "network": "supabase", "env-file": [ "${dir:state}/meta-env.env" ], "secrets-in-environment": "postgres-meta reads PG_META_DB_PASSWORD from the environment only" }, { "id": "edge-functions", "type": "container", "name": "supabase-edge-functions", "image": "supabase/edge-runtime@sha256:6f7ac3b363f6b278ff9235672a81504ad07709a07f62c50cd4fffb6708842ff1", "network": "supabase", "args": [ "start", "--main-service", "/home/deno/main" ], "volumes": [ "${dir:functions}:/home/deno/functions", "${dir:state}/functions-main/index.ts:/home/deno/main/index.ts:ro" ], "env-file": [ "${dir:state}/functions-env.env" ], "secrets-in-environment": "the edge runtime's main service hands its own environment (JWT secret, service key, database URL) to every function worker by design; there is no other channel" }, { "id": "studio", "type": "container", "name": "supabase-studio", "image": "supabase/studio@sha256:ebf492ba82db1fc9497f56e4cdebf5cddb464b61f6227e21c8f5f3693f9dbbc5", "health": { "kind": "runtime" }, "network": "supabase", "env-file": [ "${dir:state}/studio-env.env" ], "restart-on": [ "studio-env" ], "secrets-in-environment": "Studio (Next.js) reads its keys, the database password and the OpenAI key from the environment only" }, { "id": "pooler", "type": "container", "name": "supabase-pooler", "image": "supabase/supavisor@sha256:2f24ab556380db7aaf402d2ec5db09d1974739e685781a91a77ab5ae0dadb3a5", "network": "supabase", "ports": [ "5432", "6543" ], "args": [ "/bin/sh", "-c", "/app/bin/migrate && /app/bin/supavisor eval \"$(cat /etc/pooler/pooler.exs)\" && /app/bin/server" ], "volumes": [ "${dir:state}/pooler.exs:/etc/pooler/pooler.exs:ro", "${dir:state}/settings.json:/etc/pooler/settings.json:ro" ], "restart-on": [ "pooler-conf", "settings" ], "env-file": [ "${dir:state}/pooler-env.env" ], "secrets-in-environment": "Supavisor reads DATABASE_URL, SECRET_KEY_BASE, VAULT_ENC_KEY and the JWT secret from the environment only" } ], "build": { "artifacts": [ { "name": "files", "kind": "archive", "from": "files" } ] } }