Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 58 additions & 54 deletions blueprints/supabase/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
# Destroy: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
# Reset everything: ./reset.sh

name: supabase
name: ${CONTAINER_PREFIX}-supabase

services:

studio:
container_name: ${CONTAINER_PREFIX}-studio
image: supabase/studio:2025.04.21-sha-173cc56
image: supabase/studio:2026.02.16-sha-26c615c
restart: unless-stopped
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://studio:3000/api/platform/profile').then((r) => {if (r.status !== 200) throw new Error(r.status)})"
"fetch('http://${CONTAINER_PREFIX}-studio:3000/api/platform/profile').then((r) => {if (r.status !== 200) throw new Error(r.status)})"
]
timeout: 10s
interval: 5s
Expand All @@ -28,34 +28,37 @@ services:
analytics:
condition: service_healthy
environment:
STUDIO_PG_META_URL: http://meta:8080
HOSTNAME: "::"
STUDIO_PG_META_URL: http://${CONTAINER_PREFIX}-meta:8080
POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_HOST: ${POSTGRES_HOST}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION}
DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}

SUPABASE_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
AUTH_JWT_SECRET: ${JWT_SECRET}

LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
LOGFLARE_URL: http://analytics:4000
LOGFLARE_API_KEY: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
LOGFLARE_URL: http://${CONTAINER_PREFIX}-analytics:4000
NEXT_PUBLIC_ENABLE_LOGS: true
# Comment to use Big Query backend for analytics
NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
# Uncomment to use Big Query backend for analytics
# NEXT_ANALYTICS_BACKEND_PROVIDER: bigquery
SNIPPETS_MANAGEMENT_FOLDER: /app/snippets
EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions
volumes:
- ../files/volumes/snippets:/app/snippets:Z
- ../files/volumes/functions:/app/edge-functions:Z

kong:
container_name: ${CONTAINER_PREFIX}-kong
image: kong:2.8.1
restart: unless-stopped
# ports:
# - ${KONG_HTTP_PORT}:8000/tcp
# - ${KONG_HTTPS_PORT}:8443/tcp
expose:
- 8000
- 8443
Expand All @@ -70,7 +73,7 @@ services:
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
# https://github.com/supabase/cli/issues/14
KONG_DNS_ORDER: LAST,A,CNAME
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
SUPABASE_ANON_KEY: ${ANON_KEY}
Expand All @@ -83,7 +86,7 @@ services:

auth:
container_name: ${CONTAINER_PREFIX}-auth
image: supabase/gotrue:v2.171.0
image: supabase/gotrue:v2.186.0
restart: unless-stopped
healthcheck:
test:
Expand All @@ -110,27 +113,21 @@ services:
GOTRUE_API_HOST: 0.0.0.0
GOTRUE_API_PORT: 9999
API_EXTERNAL_URL: ${API_EXTERNAL_URL}

GOTRUE_DB_DRIVER: postgres
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}

GOTRUE_SITE_URL: ${SITE_URL}
GOTRUE_URI_ALLOW_LIST: ${ADDITIONAL_REDIRECT_URLS}
GOTRUE_DISABLE_SIGNUP: ${DISABLE_SIGNUP}

GOTRUE_JWT_ADMIN_ROLES: service_role
GOTRUE_JWT_AUD: authenticated
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
GOTRUE_JWT_EXP: ${JWT_EXPIRY}
GOTRUE_JWT_SECRET: ${JWT_SECRET}

GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS}
GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM}

# Uncomment to bypass nonce check in ID Token flow. Commonly set to true when using Google Sign In on mobile.
# GOTRUE_EXTERNAL_SKIP_NONCE_CHECK: true

# GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED: true
# GOTRUE_SMTP_MAX_FREQUENCY: 1s
GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL}
Expand All @@ -143,32 +140,26 @@ services:
GOTRUE_MAILER_URLPATHS_CONFIRMATION: ${MAILER_URLPATHS_CONFIRMATION}
GOTRUE_MAILER_URLPATHS_RECOVERY: ${MAILER_URLPATHS_RECOVERY}
GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE: ${MAILER_URLPATHS_EMAIL_CHANGE}

GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP}
GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM}
# Uncomment to enable custom access token hook. Please see: https://supabase.com/docs/guides/auth/auth-hooks for full list of hooks and additional details about custom_access_token_hook

# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: "true"
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI: "pg-functions://postgres/public/custom_access_token_hook"
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS: "<standard-base64-secret>"

# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED: "true"
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI: "pg-functions://postgres/public/mfa_verification_attempt"

# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED: "true"
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI: "pg-functions://postgres/public/password_verification_attempt"

# GOTRUE_HOOK_SEND_SMS_ENABLED: "false"
# GOTRUE_HOOK_SEND_SMS_URI: "pg-functions://postgres/public/custom_access_token_hook"
# GOTRUE_HOOK_SEND_SMS_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n"

# GOTRUE_HOOK_SEND_EMAIL_ENABLED: "false"
# GOTRUE_HOOK_SEND_EMAIL_URI: "http://host.docker.internal:54321/functions/v1/email_sender"
# GOTRUE_HOOK_SEND_EMAIL_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n"

rest:
container_name: ${CONTAINER_PREFIX}-rest
image: postgrest/postgrest:v12.2.11
image: postgrest/postgrest:v14.5
restart: unless-stopped
depends_on:
db:
Expand All @@ -192,7 +183,7 @@ services:
realtime:
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
container_name: realtime-dev.${CONTAINER_PREFIX}-realtime
image: supabase/realtime:v2.34.47
image: supabase/realtime:v2.76.5
restart: unless-stopped
depends_on:
db:
Expand All @@ -214,8 +205,9 @@ services:
"http://localhost:4000/api/tenants/realtime-dev/health"
]
timeout: 5s
interval: 5s
interval: 30s
retries: 3
start_period: 10s
environment:
PORT: 4000
DB_HOST: ${POSTGRES_HOST}
Expand All @@ -233,14 +225,13 @@ services:
APP_NAME: realtime
SEED_SELF_HOST: true
RUN_JANITOR: true
DISABLE_HEALTHCHECK_LOGGING: "true"

# To use S3 backed storage: docker compose -f docker-compose.yml -f docker-compose.s3.yml up
storage:
container_name: ${CONTAINER_PREFIX}-storage
image: supabase/storage-api:v1.22.7
image: supabase/storage-api:v1.37.8
restart: unless-stopped
volumes:
- ../files/volumes/storage:/var/lib/storage:z
healthcheck:
test:
[
Expand All @@ -265,22 +256,27 @@ services:
environment:
ANON_KEY: ${ANON_KEY}
SERVICE_KEY: ${SERVICE_ROLE_KEY}
POSTGREST_URL: http://rest:3000
POSTGREST_URL: http://${CONTAINER_PREFIX}-rest:3000
PGRST_JWT_SECRET: ${JWT_SECRET}
DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
FILE_SIZE_LIMIT: 52428800
STORAGE_BACKEND: file
GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET}
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
TENANT_ID: stub
TENANT_ID: ${STORAGE_TENANT_ID}
# TODO: https://github.com/supabase/storage-api/issues/55
REGION: stub
GLOBAL_S3_BUCKET: stub
REGION: ${REGION}
ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:5001
IMGPROXY_URL: http://${CONTAINER_PREFIX}-imgproxy:5001
# S3 protocol endpoint configuration
S3_PROTOCOL_ACCESS_KEY_ID: ${S3_PROTOCOL_ACCESS_KEY_ID}
S3_PROTOCOL_ACCESS_KEY_SECRET: ${S3_PROTOCOL_ACCESS_KEY_SECRET}
volumes:
- ../files/volumes/storage:/var/lib/storage:z

imgproxy:
container_name: ${CONTAINER_PREFIX}-imgproxy
image: darthsim/imgproxy:v3.8.0
image: darthsim/imgproxy:v3.30.1
restart: unless-stopped
volumes:
- ../files/volumes/storage:/var/lib/storage:z
Expand All @@ -299,10 +295,11 @@ services:
IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
IMGPROXY_USE_ETAG: "true"
IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
IMGPROXY_MAX_SRC_RESOLUTION: 16.8

meta:
container_name: ${CONTAINER_PREFIX}-meta
image: supabase/postgres-meta:v0.88.9
image: supabase/postgres-meta:v0.95.2
restart: unless-stopped
depends_on:
db:
Expand All @@ -317,24 +314,27 @@ services:
PG_META_DB_NAME: ${POSTGRES_DB}
PG_META_DB_USER: supabase_admin
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
CRYPTO_KEY: ${PG_META_CRYPTO_KEY}

functions:
container_name: ${CONTAINER_PREFIX}-edge-functions
image: supabase/edge-runtime:v1.67.4
image: supabase/edge-runtime:v1.70.3
restart: unless-stopped
volumes:
- ../files/volumes/functions:/home/deno/functions:Z
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Volume path mismatch for edge functions. The studio service mounts ./volumes/functions:/app/edge-functions:Z (line 56) but the functions service mounts ../files/volumes/functions:/home/deno/functions:Z (line 324). These are different paths on the host filesystem, which means studio and the functions runtime won't share the same edge functions. Both should reference the same directory - either both should use ./volumes/functions or both should use ../files/volumes/functions.

Suggested change
- ../files/volumes/functions:/home/deno/functions:Z
- ./volumes/functions:/home/deno/functions:Z

Copilot uses AI. Check for mistakes.
- deno-cache:/root/.cache/deno
depends_on:
analytics:
condition: service_healthy
environment:
JWT_SECRET: ${JWT_SECRET}
SUPABASE_URL: http://kong:8000
SUPABASE_URL: http://${CONTAINER_PREFIX}-kong:8000
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
# TODO: Allow configuring VERIFY_JWT per function. This PR might help: https://github.com/supabase/cli/pull/786
VERIFY_JWT: "${FUNCTIONS_VERIFY_JWT}"
CONTAINER_PREFIX: ${CONTAINER_PREFIX}
command:
[
"start",
Expand All @@ -344,7 +344,7 @@ services:

analytics:
container_name: ${CONTAINER_PREFIX}-analytics
image: supabase/logflare:1.12.0
image: supabase/logflare:1.31.2
restart: unless-stopped
# ports:
# - 4000:4000
Expand Down Expand Up @@ -378,7 +378,8 @@ services:
DB_PORT: ${POSTGRES_PORT}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_SCHEMA: _analytics
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
LOGFLARE_SINGLE_TENANT: true
LOGFLARE_SUPABASE_MODE: true
LOGFLARE_MIN_CLUSTER_SIZE: 1
Expand All @@ -394,7 +395,7 @@ services:
# Comment out everything below this point if you are using an external Postgres database
db:
container_name: ${CONTAINER_PREFIX}-db
image: supabase/postgres:15.8.1.060
image: supabase/postgres:15.8.1.085
restart: unless-stopped
volumes:
- ../files/volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
Expand Down Expand Up @@ -451,7 +452,7 @@ services:

vector:
container_name: ${CONTAINER_PREFIX}-vector
image: timberio/vector:0.28.1-alpine
image: timberio/vector:0.53.0-alpine
restart: unless-stopped
volumes:
- ../files/volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
Expand All @@ -470,7 +471,8 @@ services:
interval: 5s
retries: 3
environment:
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
CONTAINER_PREFIX: ${CONTAINER_PREFIX}
command:
[
"--config",
Expand All @@ -482,11 +484,11 @@ services:
# Update the DATABASE_URL if you are using an external Postgres database
supavisor:
container_name: ${CONTAINER_PREFIX}-pooler
image: supabase/supavisor:2.5.1
image: supabase/supavisor:2.7.4
restart: unless-stopped
ports: # expose supavisor to the host to enable db pooler connection
- ${POSTGRES_PORT}:5432
- ${POOLER_PROXY_PORT_TRANSACTION}:6543
expose: # expose supavisor ports to other services (internal network) for db pooler connections
- ${POSTGRES_PORT}
- ${POOLER_PROXY_PORT_TRANSACTION}
volumes:
- ../files/volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro,z
healthcheck:
Expand Down Expand Up @@ -525,6 +527,7 @@ services:
POOLER_DEFAULT_POOL_SIZE: ${POOLER_DEFAULT_POOL_SIZE}
POOLER_MAX_CLIENT_CONN: ${POOLER_MAX_CLIENT_CONN}
POOLER_POOL_MODE: transaction
DB_POOL_SIZE: ${POOLER_DB_POOL_SIZE}
command:
[
"/bin/sh",
Expand All @@ -533,4 +536,5 @@ services:
]

volumes:
db-config:
db-config:
deno-cache:
Loading
Loading