# Heroku

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 20 minutes
- Last updated: July 2026

## TL;DR

FlutterFlow does not get deployed to Heroku. The real relationship is: Heroku hosts your backend API (a Node.js, Python, or Rails app plus Heroku Postgres), and your FlutterFlow app calls that backend over REST. Separately, the Heroku Platform API lets you build an in-app ops panel to read dyno status and manage config vars — but only with the mandatory versioned Accept header.

## How FlutterFlow and Heroku Actually Work Together

The most common misconception among FlutterFlow founders is that you 'deploy your FlutterFlow app to Heroku' the way you might push a Node.js server. That is not how it works. FlutterFlow compiles your project into a Flutter application that runs on the user's phone or browser. Heroku is a platform for hosting server-side code — APIs, background workers, and databases. The relationship is client and server: Heroku hosts your backend, and FlutterFlow is the frontend client that calls it.

The practical setup: you or a developer deploys a REST API to Heroku (Node.js/Express, Python/FastAPI, Rails — any HTTP framework works). That API handles business logic, talks to Heroku Postgres, and returns JSON. In FlutterFlow, you create an API Group pointing at https://your-app.herokuapp.com/ and add API Calls for each endpoint your app needs. From FlutterFlow's perspective, Heroku is invisible — it just sees a base URL that returns JSON.

Heroku stopped offering free dynos in November 2022. The cheapest option is now Eco dynos at $5/month for 1,000 shared dyno-hours, followed by Basic at $7/month for an always-on single dyno. Heroku Postgres starts at around $5/month (verify current pricing at heroku.com/pricing). The Heroku Platform API at https://api.heroku.com/ lets you build an in-app ops panel to read dyno status, list apps, view config vars, or trigger restarts — useful for engineering teams who want to monitor their Heroku infrastructure from a mobile dashboard.

## Before you start

- A FlutterFlow project (any plan)
- A backend API already deployed on Heroku (or a Heroku account with API access for the ops-panel path)
- The base URL of your Heroku app (e.g. https://your-app.herokuapp.com) or the Heroku Platform API base URL
- A Heroku API key from Account Settings → API Key (only needed for the Platform API ops-panel path)
- Basic understanding of REST APIs and JSON responses

## Step-by-step guide

### 1. Frame the integration: Heroku hosts your backend, FlutterFlow calls it

Before setting up anything in FlutterFlow, it is worth pausing on a critical point that trips up almost every first-time user: FlutterFlow does not get deployed to Heroku. FlutterFlow is a frontend builder. When you publish a FlutterFlow app, it runs on the user's phone or web browser. Heroku is for the server-side code — your API, your database, your background workers.

If you already have a backend running on Heroku, your FlutterFlow app just needs to know its URL (for example, https://my-api.herokuapp.com/). Everything Heroku does — database reads, authentication logic, third-party API calls — stays on the server. FlutterFlow sends HTTP requests and reads the JSON responses. Heroku is completely invisible to the end user.

If you do not yet have a backend on Heroku and you are wondering where to host one, you have options: a Node.js/Express API, a Python/FastAPI app, or a Ruby on Rails backend are all common pairings. Once you deploy it and get a .herokuapp.com URL, you are ready to connect it to FlutterFlow. This step is about confirming you have that URL available before proceeding. FlutterFlow also cannot connect directly to Heroku Postgres — your backend must expose a REST endpoint that talks to the database for you.

For the secondary use-case — building an in-app Heroku ops dashboard using the Heroku Platform API — you will also need a Heroku API key from your account settings. Be aware: a Heroku API key can read config vars (which contain database passwords and third-party secrets), scale and restart dynos, and in some configurations delete apps. It must never ship inside your Flutter app binary.

**Expected result:** You have clarity on which path you are building: (A) FlutterFlow calling your own Heroku-hosted backend API, or (B) FlutterFlow calling the Heroku Platform API for an ops dashboard.

### 2. Create a FlutterFlow API Group for your Heroku-hosted backend

In your FlutterFlow project, click API Calls in the left navigation panel. Click + Add, then select Create API Group from the dropdown. Name the group after your app or service — for example, MyHerokuAPI. In the Base URL field, paste your Heroku app's root URL: https://your-app.herokuapp.com (replace your-app with your actual Heroku app name; it should not include a trailing slash).

If your backend requires authentication (a JWT Bearer token, an API key header, or a session cookie), add a shared header in the Headers tab of the API Group. For example, if your backend expects Authorization: Bearer [token], click + Add Header → set the key to Authorization → set the value to Bearer {{authToken}} where authToken is a variable you will populate at runtime from your app's authentication state. The {{ variable }} syntax tells FlutterFlow that this value comes from the app at runtime, not a hardcoded string.

With the group saved, click + Add again and choose Create API Call inside the group. Select the HTTP method (GET, POST, PATCH, etc.) and enter the endpoint path relative to the base URL — for example, /users or /products/{{productId}}. Define any path or query variables in the Variables tab. In the Response & Test tab, click Test API Call to confirm you get a 200 response. Paste a sample response in the text area and click Generate JSON Paths — FlutterFlow will automatically extract all the fields for you to bind to widgets.

Repeat this pattern for each endpoint your FlutterFlow app needs. You can add as many API Calls as required inside the same API Group. Once you have at least one call working, proceed to bind the response data to widgets using a Backend Query on a Page or a Column widget.

```
// Example API Call JSON config for FlutterFlow:
// Group: MyHerokuAPI
// Base URL: https://your-app.herokuapp.com

// GET /users — list all users
{
  "method": "GET",
  "endpoint": "/users",
  "headers": {
    "Authorization": "Bearer {{authToken}}",
    "Content-Type": "application/json"
  }
}

// POST /tasks — create a new task
{
  "method": "POST",
  "endpoint": "/tasks",
  "headers": {
    "Authorization": "Bearer {{authToken}}",
    "Content-Type": "application/json"
  },
  "body": {
    "title": "{{taskTitle}}",
    "due_date": "{{dueDate}}"
  }
}
```

**Expected result:** The API Group is saved with your .herokuapp.com base URL. At least one API Call tests successfully in the Response & Test tab with a 200 status and generated JSON Paths.

### 3. (Optional) Create the Heroku Platform API Group for an ops dashboard

If you want to build an in-app Heroku ops dashboard — reading app status, dyno health, or config vars — you need a separate API Group targeting the Heroku Platform API. This is a different API from your backend; it gives you programmatic control over your Heroku account.

In API Calls → + Add → Create API Group, name it HerokuPlatform and set the Base URL to https://api.heroku.com. Now add two headers to the group — these are shared across all Platform API calls:

1. Authorization: Bearer {{herokuApiKey}} — your Heroku account API key, stored in an App Constant (Settings & Integrations → App Settings → App Constants).
2. Accept: application/vnd.heroku+json; version=3 — this versioned Accept header is mandatory. Omitting it causes 406 errors or returns an unexpected payload format. This is the single most common mistake when calling the Heroku Platform API.

With both headers configured, add an API Call inside the group: GET /apps — this returns a JSON array of all your Heroku apps with their names, regions, and web URL. In Response & Test, paste a sample response and generate JSON Paths — you will get paths like $[0].name, $[0].web_url, and $[0].released_at that you can bind to a ListView. Add another API Call for GET /apps/{{appName}}/dynos to fetch dyno status for a specific app — the response includes state (up, idle, crashed) and the dyno type.

Bind the app list to a ListView using a Backend Query. Each list item shows the app name, region, and a color-coded status indicator. Tapping an app navigates to a detail screen that calls the dynos endpoint for that specific app.

Critically, the Heroku API key you store in App Constants is accessible to anyone who decompiles your APK. For a production app used by non-engineers, keep the Heroku API key in a Firebase Cloud Function and have FlutterFlow call your function. For an internal tool used only by your own engineering team on controlled devices, an App Constant is an acceptable tradeoff. Never add delete-app or config-var-write endpoints to the FlutterFlow API Group — keep destructive operations server-side only.

```
// Heroku Platform API Group configuration:
// Base URL: https://api.heroku.com
// Shared headers:
//   Authorization: Bearer {{herokuApiKey}}
//   Accept: application/vnd.heroku+json; version=3

// GET /apps — list all apps
{
  "method": "GET",
  "endpoint": "/apps"
}
// JSON Path examples:
//   App name:    $[0].name
//   Web URL:     $[0].web_url
//   Released at: $[0].released_at
//   Region:      $[0].region.name

// GET /apps/{app_name}/dynos — list dynos for one app
{
  "method": "GET",
  "endpoint": "/apps/{{appName}}/dynos"
}
// JSON Path examples:
//   Dyno type:  $[0].type
//   State:      $[0].state
//   Created at: $[0].created_at
```

**Expected result:** The HerokuPlatform API Group is saved with both required headers. GET /apps returns a list of your Heroku apps in the Response & Test tab with a 200 status. JSON Paths are generated and visible.

### 4. Bind API data to FlutterFlow widgets and test the app

With your API Groups configured, it is time to display real data in your app's UI. Navigate to the screen where you want to show Heroku data (either your own backend's data or the Platform API ops dashboard). Click on the root widget of the screen (typically a Column or ListView) to select it, then open the Backend Query panel on the right side. Select API Call, choose the API Group and the specific call you want to use, and enter any required variables (for example, the authToken from your auth state, or the appName from a Page Parameter if you are drilling into a specific Heroku app).

In a ListView, bind each list item's text widgets to the JSON Paths you generated earlier. For example, if the JSON Path $[0].name extracts the app name, set a Text widget's value to List Item → App Name (FlutterFlow uses readable labels derived from the JSON Path). For a status badge, create a Conditional Text or Container widget whose color changes based on the value of the state field — green for up, yellow for idle, red for crashed.

For the Heroku ops dashboard, add a pull-to-refresh gesture: select the ListView, scroll to the Action tab in the Properties panel, and enable Pull to Refresh — set it to re-execute the Backend Query. This gives the on-call engineer a simple way to check the latest dyno status without navigating away from the screen.

For your own Heroku-hosted backend, follow the same binding pattern for whatever data shape your API returns. Use JSON Path to navigate nested objects, and bind fields to Text, Image, Card, and other widgets as needed.

Test the full flow in FlutterFlow's browser-based Run mode for backend queries (API Calls execute normally in the web preview). Verify that the list populates correctly and that tapping a list item navigates to a detail screen with the right data. Then test on a physical device to confirm the experience feels correct in native form.

**Expected result:** Your FlutterFlow screen displays live data from your Heroku backend or the Heroku Platform API. The ListView populates with app names and dyno statuses. Pull-to-refresh re-fetches the data successfully.

## Best practices

- Never deploy the FlutterFlow app to Heroku — Heroku hosts your backend API; FlutterFlow compiles to a client app that calls it.
- Never put the Heroku API key in client Dart or FlutterFlow App Constants for production public-facing apps — it can expose config vars containing database passwords; keep it in a server-side Cloud Function.
- Always include the Accept: application/vnd.heroku+json; version=3 header on every Heroku Platform API call — omitting it causes 406 errors.
- Use Standard-1x or higher Heroku dynos for backend APIs called from a mobile app — Eco and Basic dynos sleep and cause cold-start delays that users experience as a broken app.
- Set up Heroku Postgres connection pooling (PgBouncer) on your backend if your FlutterFlow app scales to many concurrent users — raw Postgres connections are limited and expensive.
- Add CORS headers to your Heroku backend from day one — even if you start with a native mobile app, you may publish a web build later and CORS errors will be a surprise.
- Use Heroku Config Vars (not hardcoded values in your backend code) for all secrets, API keys, and environment-specific settings — they are encrypted and can be rotated without redeploying.

## Use cases

### Mobile app backed by a Node.js API deployed on Heroku

A FlutterFlow startup app uses a Node.js/Express backend on Heroku that handles user authentication, stores records in Heroku Postgres, and exposes a REST JSON API. The FlutterFlow API Group points at the .herokuapp.com URL; users never know or care that Heroku is involved — they just see a fast, responsive mobile app.

Prompt example:

```
Build a task management app where the backend REST API is hosted on Heroku at https://my-tasks-api.herokuapp.com/. Create screens to list tasks (GET /tasks), add a task (POST /tasks), and mark a task complete (PATCH /tasks/:id/complete).
```

### Ops dashboard showing Heroku dyno health

An engineering team wants a mobile ops dashboard that shows the status of all their Heroku dynos and whether any apps are cycling or erroring. A FlutterFlow screen calls the Heroku Platform API to list apps and their dyno formation, displaying a color-coded status list so on-call engineers can monitor deployments from anywhere.

Prompt example:

```
Create a 'Heroku Status' screen that lists all apps in my Heroku account with their dyno state (up, idle, crashed). Fetch from the Heroku Platform API and show a green/red indicator per app. Add a pull-to-refresh gesture.
```

### Config-var viewer for deployed environment variables

A developer app reads environment config variables from a specific Heroku app using the Platform API's /config-vars endpoint. This gives the team a quick mobile reference for which environment variables are set on production, without opening the Heroku dashboard in a browser. Write access to config vars is gated behind a server-side proxy to protect the Heroku API key.

Prompt example:

```
Show the config variables for my Heroku app 'my-prod-api' in a list with key and a masked value. Allow tapping a row to reveal the value. Read from the Heroku Platform API config-vars endpoint.
```

## Troubleshooting

### 406 Not Acceptable when calling the Heroku Platform API

Cause: The mandatory Accept: application/vnd.heroku+json; version=3 header is missing or incorrectly formatted. The Heroku Platform API requires this exact versioned Accept header on every request.

Solution: In your HerokuPlatform API Group headers, verify that the Accept header value is exactly application/vnd.heroku+json; version=3 (semicolon, space, version=3). Check for typos — this header is case-sensitive. Also confirm that it is set as a group-level shared header, not just on individual calls.

### FlutterFlow API Call returns 401 Unauthorized against the Heroku Platform API

Cause: The Bearer token is missing, expired, or incorrectly formatted. Heroku API keys are account-scoped and do not expire automatically, but they can be regenerated from Account Settings, invalidating previous keys.

Solution: Go to heroku.com → Account Settings → API Key → Reveal. Copy the current key and update your FlutterFlow App Constant. Confirm the Authorization header value is Bearer followed by a space and then the key — no extra whitespace or quotes around the key itself.

### FlutterFlow app cannot reach the Heroku backend — all API calls time out or return connection errors

Cause: Eco and Basic dynos on Heroku sleep after 30 minutes of inactivity. The first request after a sleep period takes 5-30 seconds to wake the dyno, causing an apparent timeout in FlutterFlow's default API timeout window.

Solution: Upgrade to a Standard-1x dyno ($25/month) for always-on behavior, or add a health-check endpoint to your backend and implement a warm-up ping in the FlutterFlow app's initState (before the first real API call). Alternatively, use an external service to ping your Heroku app every 20 minutes to prevent it from sleeping.

### FlutterFlow shows a CORS error when testing the Heroku backend in web preview (XMLHttpRequest error)

Cause: Your Heroku backend does not include CORS headers, so the browser blocks the request from FlutterFlow's web preview origin. This only affects web builds and the FlutterFlow browser preview; native iOS and Android builds do not enforce CORS.

Solution: Add CORS middleware to your Heroku backend. In Node.js/Express, run npm install cors and add app.use(cors()) before your routes. In Python/FastAPI, use the CORSMiddleware with the appropriate origins. Redeploy the backend to Heroku and retry the API Call in FlutterFlow.

## Frequently asked questions

### Can I deploy my FlutterFlow app directly to Heroku?

No. FlutterFlow compiles your project into a Flutter application — a mobile or web client — not a server-side application. Heroku hosts server-side code (APIs, workers, databases). You deploy your backend to Heroku and then point FlutterFlow's API Group at that backend's .herokuapp.com URL. The FlutterFlow app itself is published via FlutterFlow's own hosting, the App Store, Google Play, or a static web host.

### Can FlutterFlow connect directly to Heroku Postgres?

No. FlutterFlow has no native PostgreSQL connector — it supports Firebase Firestore, Supabase, and REST APIs out of the box. To use data from Heroku Postgres in FlutterFlow, your backend API (deployed on Heroku) must query the database and expose the results via a REST endpoint that FlutterFlow's API Group can call.

### Why did my Heroku API calls suddenly stop working after I regenerated my Heroku API key?

Heroku API keys are invalidated when regenerated — there is no grace period. After generating a new key in Heroku Account Settings, update the App Constant in your FlutterFlow project (Settings & Integrations → App Settings → App Constants) and republish your app. Previous versions of the app in users' hands will fail until they update.

### Is the Heroku Platform API safe to call directly from my FlutterFlow app?

Only for internal engineering tools with a controlled user base. A Heroku API key can read config vars (which contain your database credentials and third-party API secrets), scale dynos, and trigger restarts. For any public-facing app, route Platform API calls through a Firebase Cloud Function so the key never ships in the client binary. For a private dashboard used only by your own team on trusted devices, an App Constant is a reasonable tradeoff.

### What is the cheapest way to host a backend API on Heroku for a FlutterFlow app?

Heroku's Eco dyno plan at $5/month for 1,000 shared dyno-hours is the entry point since free dynos were removed in November 2022. Eco dynos sleep after 30 minutes of inactivity, causing cold-start delays. The Basic dyno at $7/month stays awake and is a better choice for a production mobile app. Add Heroku Postgres Essential at around $5/month for a managed database. Verify current pricing at heroku.com/pricing.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/heroku
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/heroku
