Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Connect Your FlutterFlow Project to a Third-Party Database

Connect FlutterFlow to any external database using one of three patterns: (1) Native Supabase integration via Settings → Integrations for PostgreSQL, (2) FlutterFlow API Manager for databases with REST APIs like Airtable or Hasura, or (3) Cloud Function proxy for databases without REST APIs like MySQL, PostgreSQL, or MongoDB where credentials must stay server-side. Choose based on your database type and real-time requirements.

What you'll learn

  • When to use FlutterFlow's native Supabase integration versus an API Manager group versus a Cloud Function proxy
  • How to configure FlutterFlow API Manager to query Airtable, Hasura, or any REST-enabled database
  • How to build a Cloud Function proxy that connects to MySQL or PostgreSQL and exposes REST endpoints for FlutterFlow
  • How to cache external database results in Firestore for offline support and faster reads
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate13 min read30-50 minFlutterFlow Free+ (Supabase/REST APIs); Cloud Functions require Blaze planMarch 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to any external database using one of three patterns: (1) Native Supabase integration via Settings → Integrations for PostgreSQL, (2) FlutterFlow API Manager for databases with REST APIs like Airtable or Hasura, or (3) Cloud Function proxy for databases without REST APIs like MySQL, PostgreSQL, or MongoDB where credentials must stay server-side. Choose based on your database type and real-time requirements.

Connect FlutterFlow to any external database with the right architecture for your use case

Most FlutterFlow tutorials assume you are using Firebase Firestore — but many developers have existing databases they need to connect: a PostgreSQL database running on a VPS, a MySQL database behind a company firewall, a MongoDB Atlas cluster, or a data source like Airtable. FlutterFlow cannot connect to these databases directly from the client side — database credentials in app code are a critical security risk, and most databases are not accessible via HTTP. This tutorial covers the three connection patterns and when to use each: native Supabase integration, API Manager for REST-enabled databases, and Cloud Function proxies for databases that need server-side connection management.

Prerequisites

  • A running database you want to connect (MySQL, PostgreSQL, MongoDB, Airtable, Supabase, or similar)
  • For Cloud Function proxy: Firebase project on Blaze plan and Node.js installed locally
  • For Supabase: an active Supabase project at supabase.com with your project URL and anon key
  • For REST APIs: the API documentation including base URL, authentication method, and endpoint paths

Step-by-step guide

1

Choose your connection pattern based on your database type

Before configuring anything in FlutterFlow, determine which of three patterns fits your database. Pattern 1 — Native Supabase Integration: if your database is Supabase (PostgreSQL hosted at supabase.com), use FlutterFlow's built-in integration. This is the best option — FlutterFlow has a dedicated Supabase query builder, supports real-time subscriptions, and handles auth automatically. Pattern 2 — API Manager (REST API): if your database has an HTTP REST API (Airtable's REST API, a Hasura GraphQL/REST endpoint, a custom REST API you've already built, or a managed database with REST like PlanetScale's Data API), use FlutterFlow's API Manager to call it directly. The database API handles authentication. Pattern 3 — Cloud Function Proxy: if your database has no HTTP API (MySQL, PostgreSQL, MongoDB, SQL Server, Redis), or if it is behind a firewall, or if you need connection pooling, you must build a Cloud Function that connects to the database server-side via a SDK and exposes REST endpoints for FlutterFlow. Never connect directly from the client — putting database connection strings or credentials in a Flutter app is a critical security vulnerability.

Expected result: You have selected the right connection pattern for your specific database type.

2

Connect Supabase using FlutterFlow's native integration

If your database is Supabase, skip the Cloud Function entirely — FlutterFlow has a direct integration. Go to Settings → Integrations → Supabase. Enter your Supabase Project URL (from Supabase Dashboard → Settings → API → Project URL, format: https://{ref}.supabase.co) and the Anon Key (public key, safe for client use — from the same Settings → API page). Click Connect. FlutterFlow validates the connection and shows your Supabase tables. Now, when you add a Backend Query on any page or widget, you see a Supabase Query option alongside Firestore. The query builder shows your table names, lets you add WHERE conditions, ORDER BY, LIMIT, and JOIN-like relationships. For Row Level Security: every table should have RLS enabled in Supabase Dashboard — FlutterFlow's Supabase integration sends the user's JWT automatically when a user is logged in via Supabase Auth, so RLS policies based on auth.uid() work without additional configuration. For real-time: FlutterFlow supports Supabase real-time subscriptions — enable Replication for the table in Supabase Dashboard → Database → Replication and check 'Subscribe to database changes' in the Backend Query settings.

Expected result: Supabase is connected and your tables appear in FlutterFlow's Backend Query Supabase panel. A test query returns rows from your Supabase table.

3

Query Airtable or a REST-enabled database via API Manager

For databases with REST APIs, use FlutterFlow's API Manager without any Cloud Function. Example: connecting to Airtable. Go to API Manager → Add API Group → name it Airtable. Set Base URL to https://api.airtable.com/v0/{your-base-id} (find your Base ID in Airtable's API documentation at airtable.com/api — it starts with 'app'). Under Headers, add Authorization: Bearer YOUR_AIRTABLE_TOKEN (get a Personal Access Token from airtable.com/create/tokens with data.records:read scope). Add an individual API Call named listRecords. Method: GET. Path: /{tableId} (your table name or ID). Add Query Parameters: filterByFormula=[FIELD]='value' (optional filter), maxRecords=100, sort[0][field]=Name&sort[0][direction]=asc. Click Test — the response shows your Airtable records as JSON. In the response inspector, mark the fields you need: records[].id, records[].fields.Name, records[].fields.Email, etc. Create a page with a Backend Query using listRecords. Add a ListView bound to the records array using Generate Dynamic Children. Each child displays the fields you extracted.

airtable_api_config.txt
1// API Group: Airtable
2// Base URL: https://api.airtable.com/v0/appYOUR_BASE_ID
3// Header: Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN
4//
5// Endpoint: listRecords
6// Method: GET
7// Path: /tblYOUR_TABLE_ID
8// Query Params:
9// maxRecords = 100
10// sort[0][field] = Name
11// sort[0][direction] = asc
12//
13// Optional filter param (add as variable):
14// filterByFormula = AND({Status}='Active')
15//
16// Response JSON path for binding:
17// records → array of records
18// records[].id → Airtable record ID
19// records[].fields.Name
20// records[].fields.Email
21// records[].fields.Status
22//
23// Endpoint: createRecord
24// Method: POST
25// Body:
26// {
27// "fields": {
28// "Name": "[name]",
29// "Email": "[email]",
30// "Status": "Active"
31// }
32// }

Expected result: Airtable records appear in the FlutterFlow API Manager response inspector. A test ListView page displays rows from your Airtable base.

4

Build a Cloud Function proxy for MySQL or PostgreSQL

For databases without REST APIs (MySQL, PostgreSQL, MongoDB, SQL Server), build a Cloud Function that connects via Node.js drivers and exposes REST endpoints. The Cloud Function acts as a bridge: FlutterFlow sends a POST request to the Cloud Function specifying what data to fetch or write, the Cloud Function executes the database query using the database SDK, and returns the results as JSON. The database connection string and credentials live only in Firebase Functions config — they are never exposed to the client. Use connection pooling (pg Pool for PostgreSQL, mysql2 createPool for MySQL) to reuse database connections across function invocations rather than creating a new connection for every request.

functions/index.js
1// functions/index.js — PostgreSQL proxy via Cloud Function
2// Install: cd functions && npm install pg
3const functions = require('firebase-functions');
4const admin = require('firebase-admin');
5const { Pool } = require('pg');
6
7admin.initializeApp();
8
9// Connection pool — reused across warm invocations
10const pool = new Pool({
11 host: functions.config().db.host,
12 port: functions.config().db.port || 5432,
13 database: functions.config().db.name,
14 user: functions.config().db.user,
15 password: functions.config().db.password,
16 max: 5, // max connections in pool
17 idleTimeoutMillis: 10000,
18 ssl: { rejectUnauthorized: false }, // Required for cloud DB providers
19});
20
21exports.dbProxy = functions.https.onRequest(async (req, res) => {
22 res.set('Access-Control-Allow-Origin', '*');
23 if (req.method === 'OPTIONS') { res.status(204).send(''); return; }
24
25 const { action, params } = req.body;
26 let result;
27
28 try {
29 const client = await pool.connect();
30 try {
31 if (action === 'getUsers') {
32 const r = await client.query(
33 'SELECT id, name, email, created_at FROM users ORDER BY created_at DESC LIMIT $1',
34 [params?.limit || 50]
35 );
36 result = r.rows;
37 } else if (action === 'getUserById') {
38 const r = await client.query(
39 'SELECT * FROM users WHERE id = $1',
40 [params.userId]
41 );
42 result = r.rows[0];
43 } else if (action === 'createUser') {
44 const r = await client.query(
45 'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
46 [params.name, params.email]
47 );
48 result = r.rows[0];
49 } else if (action === 'updateUser') {
50 await client.query(
51 'UPDATE users SET name = $1 WHERE id = $2',
52 [params.name, params.userId]
53 );
54 result = { success: true };
55 } else {
56 res.status(400).json({ error: 'Unknown action' });
57 return;
58 }
59 } finally {
60 client.release();
61 }
62 res.json({ success: true, data: result });
63 } catch (err) {
64 console.error('DB error:', err);
65 res.status(500).json({ success: false, error: err.message });
66 }
67});
68
69// Set config: firebase functions:config:set \
70// db.host='your.db.host' db.name='mydb' \
71// db.user='dbuser' db.password='dbpass'

Expected result: Cloud Function deployed. A POST to dbProxy with {action: 'getUsers'} returns rows from your PostgreSQL table as JSON.

5

Cache external database results in Firestore for offline support

External databases (Airtable, MySQL, PostgreSQL) do not support real-time listeners or offline access. If a user opens your FlutterFlow app without internet connectivity, they see a blank page. Add Firestore caching to solve this. In your Cloud Function (or in a separate scheduled Cloud Function), after fetching data from the external database, write it to a Firestore mirror collection. For example, after getUsers returns records, loop through them and write each to Firestore users_cache/{id}. In FlutterFlow, your primary Backend Query reads from users_cache (Firestore) for instant offline-capable display. A secondary Background sync triggers the Cloud Function every 15-30 minutes via a Firestore timestamp comparison: if lastSyncedAt is more than 15 minutes ago, call the sync Cloud Function. Add a pull-to-refresh gesture on your lists that forces a Cloud Function call and refreshes the Firestore cache. This architecture gives you offline support, instant loading, and fresh data on demand — the best of both worlds.

Expected result: Pages load instantly from Firestore cache. Data is available offline from the last sync. Pull-to-refresh triggers a live external database fetch.

Complete working example

Third-Party Database Connection Patterns
1Decision Tree: Which Pattern to Use?
2======================================
3Your DB Connection Pattern
4
5Supabase Settings Integrations Supabase (native)
6Airtable API Manager (REST API, Bearer token)
7Hasura API Manager (GraphQL/REST endpoint)
8PlanetScale API Manager (Data API)
9MySQL Cloud Function proxy (mysql2 driver)
10PostgreSQL Cloud Function proxy (pg driver)
11MongoDB Atlas Cloud Function proxy (mongoose driver) OR
12 API Manager if using Data API endpoint
13SQL Server Cloud Function proxy (mssql driver)
14Redis Cloud Function proxy (ioredis driver)
15
16Pattern 2: API Manager Setup (Airtable example)
17================================================
18API Group: Airtable
19 Base URL: https://api.airtable.com/v0/{baseId}
20 Header: Authorization: Bearer [AIRTABLE_TOKEN]
21 Calls:
22 listRecords GET /{tableId}?maxRecords=100
23 getRecord GET /{tableId}/{recordId}
24 createRecord POST /{tableId} body: {fields: {...}}
25 updateRecord PATCH /{tableId}/{recordId}
26 deleteRecord DELETE /{tableId}/{recordId}
27
28Pattern 3: Cloud Function Proxy Setup
29========================================
30Firebase config:
31 firebase functions:config:set \
32 db.host='host' db.name='db' db.user='u' db.password='p'
33
34Cloud Function: dbProxy (HTTPS onRequest)
35 Actions: getUsers, getUserById, createUser, updateUser
36 Connection: pg Pool (PostgreSQL) / mysql2 Pool (MySQL)
37 Security: parameterized queries only, no string concat
38
39Firestore Cache Architecture
40==============================
41Firestore: users_cache/{externalId}
42 fields: id, name, email, createdAt, cachedAt
43
44Firestore: sync_metadata/users
45 lastSyncedAt: Timestamp
46
47FlutterFlow Backend Query:
48 Primary: users_cache (Firestore, real-time, offline)
49 Refresh: pull-to-refresh Cloud Function updates Firestore
50
51Latency Comparison
52===================
53Firestore (cached): 50-100ms primary data source
54Airtable API: 200-400ms acceptable for direct call
55Cloud Function + DB: 300-600ms for writes + initial load
56Cold start CF: 1000-2000ms only on first call

Common mistakes when connecting Your FlutterFlow Project to a Third-Party Database

Why it's a problem: Connecting directly to a MySQL or PostgreSQL database from FlutterFlow's API Manager by exposing a TCP connection over HTTP

How to avoid: Build a Cloud Function that connects to MySQL/PostgreSQL using the pg or mysql2 Node.js driver. The Cloud Function exposes an HTTPS endpoint that FlutterFlow can call. Database credentials stay in Firebase Functions config on the server — they never touch the client app.

Why it's a problem: Skipping connection pooling in the Cloud Function and creating a new database connection on every request

How to avoid: Use pg Pool (PostgreSQL) or mysql2.createPool() (MySQL) declared at the module level — outside the function handler. Cloud Functions reuse warm instances, so the pool persists across invocations. Set max to 5-10 connections per function instance and configure connection timeouts.

Why it's a problem: Fetching all records from an external database on every page load without pagination or caching

How to avoid: Always add LIMIT and OFFSET (or cursor-based pagination) to database queries. Cache results in Firestore for instant display. Only fetch fresh data when explicitly needed (pull-to-refresh) or on a schedule. Display the most recent or relevant subset of data, not everything.

Best practices

  • Choose Supabase for new projects that need a relational database — the native FlutterFlow integration is far simpler than building a Cloud Function proxy for PostgreSQL
  • Always proxy external database calls through Cloud Functions — never expose database credentials in client-side API Manager headers or app code
  • Use connection pooling in Cloud Functions (pg.Pool or mysql2.createPool) declared at module level to reuse connections across warm function invocations
  • Cache external database results in Firestore to provide offline support and sub-100ms load times for read-heavy pages
  • Use parameterized queries in all database operations — string concatenation of user input into SQL queries creates SQL injection vulnerabilities
  • Implement pagination in all list queries — limit results to 20-50 records per page with cursor-based or offset pagination
  • Add a lastSyncedAt timestamp display to pages showing cached data so users know when the data was last refreshed

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I have a PostgreSQL database and want to connect it to my FlutterFlow app. Write a Firebase Cloud Function in Node.js that: (1) uses the pg library with connection pooling (Pool), (2) connects using credentials from Firebase Functions config, (3) handles these actions via POST: getCustomers (SELECT id, name, email, created_at FROM customers LIMIT 50), getCustomerById (SELECT * FROM customers WHERE id = $1), createCustomer (INSERT INTO customers), and updateCustomerStatus (UPDATE customers SET status = $1 WHERE id = $2). Include parameterized queries and proper error handling.

FlutterFlow Prompt

Connect my FlutterFlow project to Supabase by going to Settings → Integrations → Supabase, entering the Project URL and Anon Key. Then create a Backend Query on the Products page that reads from the products table where is_active equals true, ordered by created_at descending, limited to 20 results.

Frequently asked questions

Can I connect to a database behind my company firewall?

Yes, but it requires network configuration. Your Cloud Function needs to reach the database server. Options: (1) Whitelist the Cloud Function's IP range in your firewall — Firebase Cloud Functions uses Google Cloud's IP ranges (you can get the current list from cloud.google.com/vpc/docs/configure-private-google-access). (2) Use a VPC connector — Firebase Cloud Functions can connect to a Google Cloud VPC, and you can set up Cloud VPN or Interconnect from your corporate network to GCP. (3) Expose a specific port on your database server to only the whitelisted IPs. This setup requires your company's network team involvement.

How do I handle authentication when connecting to an external database?

For the database connection itself, credentials live in Firebase Functions config (server-side only). For data access security: if different users should see different data, verify the user's Firebase Auth token in the Cloud Function before executing the query. Check the Authorization header contains a valid Firebase ID token using admin.auth().verifyIdToken(token), then use the decoded token's uid to filter the database query to that user's data.

What is the latency difference between Firestore and an external database?

Firestore: 50-100ms for reads (same region). Airtable REST API: 200-400ms. Cloud Function + PostgreSQL (warm instance): 300-600ms. Cloud Function cold start + PostgreSQL: 1,000-2,000ms. For optimal UX, use Firestore as the primary read source (cache external DB data there) and only call the Cloud Function for writes and cache refresh. This gives Firestore's 50-100ms read speed with any backend database.

Can I use MongoDB Atlas with FlutterFlow?

Yes via two approaches. (1) MongoDB Atlas Data API: Atlas provides a REST API endpoint for CRUD operations — use FlutterFlow's API Manager with the endpoint https://data.mongodb-api.com/app/{appId}/endpoint/data/v1 and your API key in headers. (2) Cloud Function: use the mongoose or mongodb Node.js driver in a Cloud Function with connection pooling. The Data API approach is simpler but has limitations on complex queries. The Cloud Function approach supports all MongoDB query operators.

Does FlutterFlow support SQL queries directly?

Only for Supabase — FlutterFlow's native Supabase integration has a query builder that generates SQL-like queries (SELECT, WHERE, ORDER BY, JOIN). For all other SQL databases (MySQL, PostgreSQL, SQL Server), you write SQL in a Cloud Function's Node.js code, not in FlutterFlow directly. FlutterFlow only sends an action name and parameters to the Cloud Function; the actual SQL lives in the server-side Cloud Function code.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.