# GitHub

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

## TL;DR

Connecting FlutterFlow to GitHub means two different things: the built-in one-way code push to a 'flutterflow' branch (Growth plan, $80/month, native feature), or building GitHub-powered features into your app — a repo browser, issue tracker, or stars dashboard — via the GitHub REST API as an API Group with a fine-grained Personal Access Token. Most founders searching this want the native code push.

## The Two Meanings of 'Connect FlutterFlow to GitHub'

When FlutterFlow users search for how to connect to GitHub, they almost always mean the platform's built-in code export: FlutterFlow generates Flutter/Dart code from your visual design and pushes it to a GitHub repository. This is a genuine native feature available on the Growth plan ($80/month) and above. It lets you version-control your generated code, create CI/CD pipelines from it (with GitHub Actions), and hand off the code to a developer who continues in a code editor. GitHub itself is free for unlimited public and private repositories — the cost is on the FlutterFlow side, not GitHub's.

The second meaning is building GitHub-powered screens into your running Flutter app: a repository browser for an open-source community app, an issue tracker for a developer tool, a contributor leaderboard for a hackathon platform. These features use the GitHub REST API at `https://api.github.com/` as a FlutterFlow API Group with a fine-grained Personal Access Token. Unauthenticated calls to the GitHub API are limited to 60 requests per hour — easily exhausted by a busy screen — so always authenticate. Authenticated requests get 5,000 requests per hour, which is sufficient for most in-app use cases.

This page handles both paths. It starts with the native push because that is the dominant intent, then explains the in-app API Group setup. If you are a developer who wants to keep editing code after export, the native push plus a 'never touch the flutterflow branch' rule is the key discipline. If you are building a community or developer tool app, the API Group path is your route.

## Before you start

- A FlutterFlow account on the Growth plan ($80/month) or higher for the native GitHub push feature; any plan works for the in-app GitHub API Group
- A GitHub account (free tier is sufficient for unlimited public and private repositories)
- For the native push: a GitHub repository (or let FlutterFlow create one) — you'll authorize FlutterFlow via GitHub OAuth
- For the in-app API: a fine-grained GitHub Personal Access Token generated at GitHub Settings → Developer Settings → Personal Access Tokens → Fine-grained tokens, scoped to only the repositories and permissions your app needs
- Basic understanding of branches in Git if using the native code push (knowing the difference between the 'flutterflow' branch and 'main' is essential)

## Step-by-step guide

### 1. Enable the native FlutterFlow GitHub push (Growth plan+)

The native GitHub integration pushes FlutterFlow's generated Flutter/Dart code to a branch called `flutterflow` in a GitHub repository of your choice. To enable it, you must be on the Growth plan ($80/month) or higher — this is the most common surprise for founders who discover the feature is plan-gated after expecting it to be free.

To connect: in the FlutterFlow toolbar, click the GitHub icon (it looks like the GitHub Octocat logo, in the top-right area of the editor), OR go to Settings & Integrations → GitHub. Click Connect GitHub — this opens a GitHub OAuth window asking you to authorize FlutterFlow's GitHub App for your GitHub account or organization. Grant the permissions.

After authorization, you'll be prompted to select or create a repository. You can create a new repository directly from this screen, or point to an existing one. FlutterFlow will create the `flutterflow` branch if it doesn't exist.

Once connected, a Push to GitHub button appears in the FlutterFlow toolbar. Click it to push your current project state to the `flutterflow` branch. The push happens in the cloud — no local git client needed. You can push as often as you like; each push reflects FlutterFlow's current generated code state.

Note: FlutterFlow pushes only the generated code. Custom files you or a developer add inside the repository (on `main` or other branches) are invisible to FlutterFlow — it only manages the `flutterflow` branch.

**Expected result:** The GitHub icon in the FlutterFlow toolbar shows as connected, and a Push to GitHub button is available. Clicking it creates or updates the 'flutterflow' branch in your repository.

### 2. Set up the 'never touch the flutterflow branch' merge workflow

This step is critical and skipping it leads to lost work. FlutterFlow's sync is one-way: FlutterFlow pushes to the `flutterflow` branch, and nothing from GitHub syncs back into FlutterFlow. Every time you click Push to GitHub, FlutterFlow overwrites the entire `flutterflow` branch with freshly generated code.

This means: if you or a developer edit files directly on the `flutterflow` branch, those edits will be silently destroyed the next time anyone pushes from FlutterFlow. The correct workflow is:

1. FlutterFlow pushes generated code to the `flutterflow` branch.
2. On GitHub (github.com, in your browser — no terminal needed), open a Pull Request from `flutterflow` into `main` (or `develop`, or whatever your trunk branch is).
3. Merge the PR. Now `main` contains the latest generated code.
4. Your developer creates a new branch off `main` for their custom Dart additions and edits only there.
5. Developer work is merged back into `main` via a separate PR — never touching `flutterflow`.

To create the PR on GitHub without a terminal: navigate to your repository → click Pull Requests → New pull request → select `flutterflow` as the compare branch and `main` as the base → click Create pull request → Merge. This workflow can be done entirely in the browser, no command line needed.

If you use GitHub Actions for CI/CD, create a workflow that triggers on pushes to `main` (not `flutterflow`) so it runs after the merge, not immediately after FlutterFlow's raw push.

**Expected result:** You have a clear understanding of the one-way sync model, and you or your developer can safely add custom code on a 'main' branch without it being overwritten by FlutterFlow pushes.

### 3. Create a GitHub API Group for in-app GitHub features

If you want to build GitHub-powered features inside your running FlutterFlow app — a repo browser, issue list, PR dashboard, or contributor viewer — you'll use the GitHub REST API as a FlutterFlow API Group. This is independent of the native push and works on any FlutterFlow plan.

First, generate a fine-grained Personal Access Token on GitHub: go to GitHub → Settings → Developer Settings → Personal Access Tokens → Fine-grained tokens → Generate new token. Set the token's name (e.g., 'FlutterFlow App Read-Only'), set an expiration date, select the repositories the token should access (choose specific repos rather than 'All repositories' for least privilege), and select only the permissions your app needs. For a read-only repo browser: grant 'Contents: Read', 'Issues: Read', 'Metadata: Read'. Copy the generated token — you'll see it only once.

In FlutterFlow, click API Calls in the left nav → + Add → Create API Group. Set:
- **Group Name:** `GitHub`
- **Base URL:** `https://api.github.com/`
- **Headers:**
  - `Authorization`: `Bearer [App Constant: GITHUB_PAT]`
  - `Accept`: `application/vnd.github+json`
  - `X-GitHub-Api-Version`: `2022-11-28`

Store the PAT as an App Constant (Settings & Integrations → App Settings → App Constants, constant name: `GITHUB_PAT`). The `Accept` header is important — without it, GitHub may return a different media type or an older API version. The `X-GitHub-Api-Version` header pins you to a specific stable API version, which prevents breaking changes from affecting your app.

```
{
  "api_group_name": "GitHub",
  "base_url": "https://api.github.com/",
  "headers": [
    {
      "name": "Authorization",
      "value": "Bearer [App Constant: GITHUB_PAT]"
    },
    {
      "name": "Accept",
      "value": "application/vnd.github+json"
    },
    {
      "name": "X-GitHub-Api-Version",
      "value": "2022-11-28"
    }
  ]
}
```

**Expected result:** The GitHub API Group appears in your API Calls panel with all three headers configured and the PAT stored as an App Constant.

### 4. Add a GitHub API Call and bind data to widgets

With the GitHub API Group created, add individual API Calls for the features your app needs. Here's how to build a repository list call:

Inside the GitHub API Group, click + Add API Call:
- **Call Name:** `GetRepoIssues`
- **Method:** GET
- **Endpoint (relative):** `repos/OWNER/REPO/issues?state=open&per_page=30`

Replace `OWNER` and `REPO` with your organization/username and repository name, or add them as Variables so the call works dynamically across repos. To add a variable: click the Variables tab → + Add Variable, name it `owner`, then reference it in the endpoint as `repos/[owner]/[repo]/issues?state=open`.

In the Response & Test tab, click Test to fire the request. If you get a 200, you'll see a JSON array of issue objects. Click + Add JSON Path to extract fields:
- `issue_title` → `$[*].title`
- `issue_number` → `$[*].number`
- `issue_state` → `$[*].state`
- `issue_author` → `$[*].user.login`
- `issue_labels` → `$[*].labels[*].name`

In your FlutterFlow UI, add a ListView, open its Backend Query panel, select the GitHub API Group and GetRepoIssues call, and bind the response fields to Text widgets inside the list item. Set a 30-second refresh interval if you want near-real-time issue updates.

For write operations (creating issues, commenting, closing issues), the same API Group works, but use POST or PATCH methods, and consider routing those calls through a Firebase Cloud Function if your PAT has write scopes — write-capable PATs should never ship in a client binary that users can reverse-engineer.

```
{
  "call_name": "GetRepoIssues",
  "method": "GET",
  "endpoint": "repos/[owner]/[repo]/issues?state=open&per_page=30",
  "variables": [
    { "name": "owner", "type": "String" },
    { "name": "repo", "type": "String" }
  ],
  "json_paths": [
    { "name": "issue_title", "path": "$[*].title" },
    { "name": "issue_number", "path": "$[*].number" },
    { "name": "issue_state", "path": "$[*].state" },
    { "name": "issue_author", "path": "$[*].user.login" }
  ]
}
```

**Expected result:** The GetRepoIssues API Call returns a 200 response in the Test panel, and the JSON Path extractions correctly surface issue titles, numbers, and authors.

### 5. Handle GitHub webhooks via Firebase Cloud Functions

GitHub webhooks allow your application to react to events — a developer pushing code, a PR being opened, an issue being closed — in near-real-time. However, FlutterFlow is a client-side Flutter app: it cannot listen on a port or receive incoming HTTP requests. There is no direct path from GitHub's webhook system into a FlutterFlow app.

The solution is a two-step relay:

**Step 1 — Firebase Cloud Function as the webhook receiver:** Deploy a Firebase Cloud Function with an HTTPS trigger. GitHub will send webhook POST requests to this function's URL. The function verifies the webhook signature (using the `x-hub-signature-256` header and your webhook secret), extracts the event payload, and writes the relevant data to a Firestore collection (e.g., `github_events`).

**Step 2 — FlutterFlow reads from Firestore:** Your FlutterFlow app uses its native Firebase/Firestore integration to listen to the `github_events` collection with a real-time listener. When a new document appears (a new push, a new issue), the app's UI updates automatically — a new item in a list, a toast notification, a status badge change.

This pattern is the standard approach for any webhook-to-FlutterFlow relay. The Cloud Function is the public-facing receiver; Firestore is the message bus; FlutterFlow is the read client. You never need to reconfigure FlutterFlow when GitHub's webhook fires — the Firestore real-time listener handles it.

If you'd rather skip configuring Firebase Cloud Functions yourself, RapidDev's team builds FlutterFlow integrations like this every week — free scoping call at rapidevelopers.com/contact.

```
// Firebase Cloud Function: receive GitHub webhooks
// Deploy via Firebase Console → Functions
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const crypto = require('crypto');
admin.initializeApp();

exports.githubWebhook = functions.https.onRequest(async (req, res) => {
  const secret = process.env.GITHUB_WEBHOOK_SECRET;
  const sig = req.headers['x-hub-signature-256'];
  const hmac = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(req.body))
    .digest('hex');
  if (`sha256=${hmac}` !== sig) {
    return res.status(401).send('Invalid signature');
  }
  const event = req.headers['x-github-event'];
  const payload = req.body;
  await admin.firestore().collection('github_events').add({
    event,
    repo: payload.repository?.full_name,
    action: payload.action,
    sender: payload.sender?.login,
    timestamp: admin.firestore.FieldValue.serverTimestamp(),
  });
  res.status(200).send('OK');
});
```

**Expected result:** GitHub webhook events flow into Firestore via the Cloud Function, and your FlutterFlow app's Firestore listeners update the UI in real-time when relevant GitHub events occur.

## Best practices

- Treat the 'flutterflow' branch as read-only for humans — only the FlutterFlow GitHub App should write to it; all developer customizations go on 'main' or feature branches.
- Use fine-grained PATs with the minimum required scopes — a read-only token for a repo browser app, not a full-access token that can delete repositories.
- Store the GitHub PAT as an App Constant (Settings & Integrations → App Settings → App Constants); never hardcode it in API Call header fields or Custom Action Dart strings.
- Route write operations (creating issues, merging PRs, commenting) through a Firebase Cloud Function, not directly from the FlutterFlow client — write-capable PATs must not ship in a compiled app binary.
- Always include both the 'Accept: application/vnd.github+json' and 'X-GitHub-Api-Version' headers in your GitHub API Group to ensure consistent API behavior across GitHub API updates.
- For GitHub webhooks, use a Cloud Function as the HTTPS receiver and Firestore as the relay to FlutterFlow — the app cannot receive incoming HTTP requests directly.
- Set a PAT expiration date and put a calendar reminder to rotate it before it expires; an expired token causes silent 401 errors in your published app.

## Use cases

### Version-controlling a FlutterFlow app with GitHub and CI/CD

A SaaS startup builds their mobile app in FlutterFlow and wants to maintain a full Git history of generated code changes, run automated lint checks with GitHub Actions, and give their hired Flutter developer access to the codebase for custom extensions. They enable the native GitHub push, push each FlutterFlow session to the 'flutterflow' branch, and the developer merges it into 'main' before running CI. The developer's custom Dart code lives only on 'main' — never on the 'flutterflow' branch.

Prompt example:

```
I want to push my FlutterFlow project to GitHub so my developer can see the generated code and add custom Dart files. Help me set up the native FlutterFlow GitHub integration and explain how the branch workflow prevents the developer's code from being overwritten.
```

### Open-source repository browser app built in FlutterFlow

A coding bootcamp builds a companion app for students to browse the bootcamp's open-source curriculum repositories, star them from the app, and view recent commits. FlutterFlow calls the GitHub REST API as an API Group, fetching repo details, commit lists, and star counts. A fine-grained PAT scoped to read-only repository access powers all the calls. Students log into the app with their own credentials, not the bootcamp's PAT.

Prompt example:

```
Build a screen that lists GitHub repositories for the organization 'my-bootcamp-org' using the GitHub REST API, shows the repo name, star count, and last updated date, and links to the repo URL when tapped. Authenticate with a PAT stored as an App Constant.
```

### Developer tool app with live GitHub issue tracking

A team building internal tooling creates a FlutterFlow app for project managers to view and update GitHub issues without opening a browser. The app fetches open issues from a repository via the GitHub API, displays them in a ListView with labels and assignees, and lets managers close or comment on issues through PATCH and POST calls. Write-scope calls are routed through a Firebase Cloud Function so the PAT with write permissions never ships in the client binary.

Prompt example:

```
Create an issue tracker screen that fetches all open issues from 'my-org/my-repo' via the GitHub REST API, shows title, labels, and assignee avatar, and has a 'Close Issue' button that sends a PATCH request to update the issue state to 'closed'.
```

## Troubleshooting

### The GitHub icon is grayed out or 'Push to GitHub' is missing from the FlutterFlow toolbar

Cause: GitHub code push is available only on the Growth plan ($80/month) or higher. Free and Starter plan accounts don't have access to this feature.

Solution: Upgrade your FlutterFlow account to the Growth plan at FlutterFlow's pricing page. If you are on Growth and the button is still missing, sign out and back in to refresh plan entitlements. For in-app GitHub API features (repo browser, issue tracker), any plan works — that path doesn't require Growth.

### FlutterFlow pushed code to GitHub and my developer's custom files on the 'flutterflow' branch are gone

Cause: FlutterFlow's GitHub push completely replaces the 'flutterflow' branch with freshly generated code on every push. Any edits made directly to that branch are overwritten.

Solution: Establish the merge workflow: FlutterFlow owns the 'flutterflow' branch; developers work on 'main' or feature branches. After each FlutterFlow push, open a PR on GitHub from 'flutterflow' into 'main' and merge it. Developer customizations live only on 'main' or feature branches, never on 'flutterflow'. Going forward, add a branch protection rule to prevent direct edits to the 'flutterflow' branch.

### GitHub API Call returns 401 Unauthorized

Cause: The Personal Access Token is missing, expired, or the App Constant is not correctly referencing it in the Authorization header.

Solution: Check that your GitHub PAT hasn't expired (GitHub fine-grained tokens expire at the date you set when generating them). Generate a new token if needed and update the App Constant value. Verify the header is set to exactly `Bearer [App Constant: GITHUB_PAT]` — missing the word 'Bearer' or the space is a common mistake.

### GitHub API returns data but the Accept header warning appears, or JSON responses look unexpected

Cause: The `Accept: application/vnd.github+json` header is missing or set to `application/json`, which can cause GitHub to return an older API format or different response structure.

Solution: In your GitHub API Group's headers, ensure `Accept` is set to `application/vnd.github+json` (not `application/json`). Also add the `X-GitHub-Api-Version: 2022-11-28` header to pin the API version. Re-test the affected API Calls in the Response & Test tab.

### Rate limit hit: GitHub API returns 403 or 429 with 'API rate limit exceeded'

Cause: Unauthenticated GitHub API calls are limited to 60 requests/hour. Even authenticated calls (5,000/hour) can be exhausted if your app polls very frequently or loads many repos/issues simultaneously.

Solution: Ensure your API Group's Authorization header is correctly sending the PAT — unauthenticated calls are the most common cause. If already authenticated, increase the Backend Query refresh interval and use `per_page` to reduce the number of calls. Check the `x-ratelimit-remaining` header in test responses to see how many requests you have left.

## Frequently asked questions

### Does the FlutterFlow GitHub integration sync code changes from GitHub back into FlutterFlow?

No — the sync is strictly one-way. FlutterFlow pushes generated code to GitHub; nothing from GitHub flows back into FlutterFlow's visual designer. If a developer adds custom Dart files or modifies files on 'main', those changes are invisible to FlutterFlow and won't affect your visual canvas. This is by design: FlutterFlow generates code from your visual project state, and manual code edits don't map back to visual components.

### Can I use the GitHub integration on the FlutterFlow free plan?

The native GitHub code push (exporting generated Flutter code to a GitHub branch) requires the Growth plan at $80/month. However, building in-app GitHub API features — a repo browser, issue tracker, or any screen that calls the GitHub REST API — works on all FlutterFlow plans, including free. These are two separate things: the native push exports your app's code; the API Group uses GitHub as a data source inside your running app.

### What happens if I delete the GitHub repository that FlutterFlow is connected to?

FlutterFlow will lose its connection and display an error when you try to push. You would need to re-authorize and connect to a new (or recreated) repository. Your FlutterFlow project itself is unaffected — the visual design and configuration live in FlutterFlow's cloud, not in GitHub. GitHub only holds the generated code, not the source-of-truth project data.

### Can FlutterFlow receive GitHub webhook events directly?

No — FlutterFlow compiles to a client-side Flutter app that cannot listen on a port or receive incoming HTTP requests. To react to GitHub events (push, PR, issue) in your FlutterFlow app, deploy a Firebase Cloud Function as the webhook receiver. The function verifies the webhook signature, extracts the event, and writes it to Firestore. Your FlutterFlow app reads from Firestore with a real-time listener and updates its UI when new events arrive.

### Is it safe to store a GitHub Personal Access Token as a FlutterFlow App Constant?

App Constants are compiled into the Flutter binary, which means a determined attacker can extract them from a distributed APK. For read-only tokens scoped to public repository data, the risk is limited — someone could read your public repos, which they could do unauthenticated anyway. For write-capable tokens (creating issues, managing repos), you should never ship them in the client. Route write operations through a Firebase Cloud Function that holds the write-scoped token in a secure server-side environment variable.

---

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