Fly.io + Supabase Security
Fly.io deploys containers globally close to users, while Supabase provides the database. Cross-region latency and secret synchronisation across machines add unique security dimensions.
Why Fly.io + Supabase?
Fly.io's full container deployment model suits backend applications — APIs, workers, and full-stack servers — that use Supabase as a managed Postgres backend. The combination is popular for latency-sensitive apps needing a globally-distributed server layer.
Common Vulnerabilities
These are the security issues we find most often in Fly.io apps using Supabase.
Service Role Key in Dockerfile or fly.toml
Developers may hardcode Supabase credentials in Dockerfile ENV instructions or fly.toml files, which are committed to version control.
Missing RLS When Using Service Role for Performance
Fly.io apps often use the service_role key for all Supabase queries to avoid JWT overhead in latency-sensitive paths. This bypasses RLS and requires manual authorisation logic that is easily missed.
Supabase Connection Pooler Misconfiguration
High-concurrency Fly.io apps may misconfigure PgBouncer connection pooling, causing session-level settings (including auth context) to leak between requests.
Secrets Not Set Per App in Multi-App Deployments
When running separate Fly apps (API and worker), teams often share environment variables directly between them rather than setting secrets independently, increasing credential exposure surface.
What We Check for Fly.io + Supabase
Fly Secrets Configuration
Verify all Supabase credentials are set via fly secrets set and not present in Dockerfile, fly.toml, or version-controlled .env files.
Service Key vs Anon Key Usage
Audit application code for service_role key usage and verify each instance either passes user JWT to Supabase or manually enforces equivalent access control.
RLS Effective Verification
For tables accessed via service_role, confirm the application code applies equivalent access restrictions to what RLS policies would enforce.
Connection Pool Session Isolation
Check that the transaction-mode pooler (port 6543) is used for stateless deployments to avoid session leakage between requests.
Quick Security Wins
Apply these fixes right now to improve your security.
Set secrets properly: fly secrets set SUPABASE_SERVICE_ROLE_KEY=your_key — never add to Dockerfile ENV or fly.tomlAdd .env and fly.toml to .gitignore to prevent accidental credential commitsUse the anon key with user JWTs for most queries so Supabase RLS handles authorisation automaticallyConnect to Supabase via the transaction-mode pooler (port 6543) for containerised deploymentsEnable RLS on all tables even if using service_role — it provides a safety net when you switch query modesThe Bottom Line
Fly.io + Supabase is a powerful pairing for latency-sensitive, globally-distributed backends. The service_role key and secret management in multi-machine deployments are the two areas requiring deliberate security attention.
Secure Your Fly.io + Supabase App
Find Row Level Security misconfigurations, exposed credentials, and other vulnerabilities before attackers do.
Start Security ScanFrequently Asked Questions
How do Fly.io secrets differ from environment variables for Supabase credentials?
Fly secrets are encrypted at rest and injected as environment variables at runtime — they do not appear in your Dockerfile or fly.toml. Always use fly secrets set for Supabase credentials rather than ENV instructions in Dockerfiles, which end up in the image layer and are visible in your git history.
Should I use service_role key in a Fly.io backend API?
It is acceptable for server-side API code to use service_role when it validates user identity itself before any database operation. The risk is that this pattern requires you to replicate RLS logic in application code. A safer approach: pass the user's JWT in the Authorization header when creating the Supabase client so RLS applies automatically.
What Supabase connection mode should I use for Fly.io containers?
Use the transaction-mode pooler (Supabase pooler port 6543) for ephemeral Fly machines. Session mode retains state between queries, which causes problems when connection pools reuse sessions across different users in short-lived containers.
How do I keep Supabase credentials consistent across Fly.io regions?
Fly secrets are global across all machines in an app by default. Run fly secrets set once and the value is available to all machines in all regions. If you have multiple Fly apps (e.g. API and worker), set secrets independently for each app to avoid cross-app credential sharing.