Connect FlutterFlow to Docker by exporting your project (Pro plan required) and writing a two-stage Dockerfile: a Flutter build stage that compiles flutter build web --release, and an Nginx alpine stage that serves the static output. Docker lets you self-host the FlutterFlow web app or run it in CI/CD pipelines — you cannot containerize the FlutterFlow editor itself.
| Fact | Value |
|---|---|
| Tool | Docker |
| Category | DevOps & Tools |
| Method | Custom Action (Dart) |
| Difficulty | Intermediate |
| Time required | 40 minutes |
| Last updated | July 2026 |
What You Can (and Cannot) Containerize with Docker
A common question from FlutterFlow users exploring Docker is: 'Can I run FlutterFlow itself in a Docker container?' The answer is no — FlutterFlow is a hosted SaaS browser application that runs on Vercel/cloud infrastructure owned by the FlutterFlow team. There is no self-hostable FlutterFlow server to containerize. What you can containerize is the Flutter app that FlutterFlow generates for you.
FlutterFlow supports three output targets: iOS, Android, and web. Of these, only the web target is meaningful for Docker, because Docker containers run on Linux servers without screens — they can serve a web page over HTTP, but they cannot display a native mobile UI. When you run flutter build web --release, FlutterFlow's exported project produces a static bundle in build/web/ containing an index.html, a main.dart.js, Flutter's WASM engine, and your app's assets. This static bundle has no server-side runtime requirements — it just needs a web server to deliver the files to a browser. Nginx in an alpine container is the perfect fit: it's tiny (under 10 MB), handles static file serving fast, and adds no unnecessary dependencies.
The multi-stage Docker pattern keeps image sizes small by separating the heavy Flutter build environment (which is several gigabytes) from the lightweight Nginx serving environment. The final image users pull and run contains only Nginx and your compiled Flutter web files — typically under 50 MB total. For mobile targets (APK/IPA), Docker can still be part of your workflow as the CI build environment that compiles the binaries, but the output is a file you distribute through app stores, not a running container.
Integration method
FlutterFlow generates a standard Flutter codebase when you export your project. The web target of that code — compiled with flutter build web --release — produces a static folder of HTML, JavaScript, and WASM files that any web server can host. A multi-stage Dockerfile uses a Flutter-ready base image for the build step, then copies the output into a lightweight Nginx alpine image for serving. The result is a portable Docker image of your FlutterFlow web app that runs identically on your laptop, a CI runner, or any cloud that accepts containers.
Prerequisites
- FlutterFlow Pro plan ($70/month) — code export (Download Code or GitHub push) requires Pro
- Docker Desktop installed on your Mac or Windows machine (free for personal use; check current Docker licensing for commercial teams)
- The exported FlutterFlow Flutter project on your local machine — via ZIP download or GitHub clone
- Flutter SDK installed locally if you want to test the build step outside Docker before containerizing
- A container registry account (Docker Hub, GitHub Container Registry, or GitLab Container Registry) if you plan to push the image for deployment
Step-by-step guide
Export the FlutterFlow project and get it onto your machine
Containerizing starts with having the FlutterFlow source code locally. In FlutterFlow, with a Pro plan active, use one of two export paths: click the Download Code button (or find it in the top toolbar menu) to download a ZIP of the entire Flutter project, then unzip it to a folder on your computer like `~/Projects/my-app/`. Alternatively, use Settings → Integrations → GitHub to push the project to a GitHub repository, then clone that repository to your machine. Either way you end up with a standard Flutter project folder — you should see `pubspec.yaml` at the root alongside `lib/`, `android/`, `ios/`, and `web/` directories. Confirm the web/ directory exists (it typically does in FlutterFlow exports as the web platform files are included by default). This folder is where your Dockerfile will live alongside the Flutter source. If you want to verify the build works before adding Docker, open a terminal, navigate to this folder, and run `flutter pub get` followed by `flutter build web --release`. If the build succeeds, you'll see a `build/web/` directory appear. This is exactly what Nginx will serve inside the Docker container. Note: you do NOT need Flutter installed locally to build inside Docker — the build stage handles it — but a local test can catch problems earlier.
Pro tip: If flutter build web --release fails locally due to null safety errors or missing web support, run flutter create --platforms=web . inside the project directory to add web platform support, then retry.
Expected result: The FlutterFlow Flutter project folder is on your machine, with pubspec.yaml at the root. Optionally, build/web/ exists from a local build test.
Write the multi-stage Dockerfile at the project root
A multi-stage Dockerfile solves the image-size problem: the first stage (the builder) uses a large Flutter SDK image to compile your app, and the second stage (the runner) copies only the compiled static files into a tiny Nginx image. Create a new file named exactly `Dockerfile` (no extension) at the root of your Flutter project — the same level as `pubspec.yaml`. The builder stage uses `ghcr.io/cirruslabs/flutter:stable` as the base image (this is a well-maintained Flutter image from the Cirrus CI project). It copies your project files, runs `flutter pub get` to install dependencies, then runs `flutter build web --release` to compile the app. The output appears in `build/web/`. The runner stage starts fresh from `nginx:alpine` — one of the smallest usable web server images. It copies the `build/web/` directory from the builder stage into Nginx's default web root at `/usr/share/nginx/html`. An optional custom `nginx.conf` handles the single-page app routing: Flutter web uses client-side routing, so any URL path should fall back to `index.html` rather than returning a 404. Without this configuration, deep links (e.g., `/profile/settings`) will show an Nginx 404 page instead of loading the Flutter app. The Dockerfile below includes this SPA routing config inline.
1# Stage 1: Build the Flutter web app2FROM ghcr.io/cirruslabs/flutter:stable AS builder34WORKDIR /app56# Copy project files7COPY . .89# Install dependencies10RUN flutter pub get1112# Build for web in release mode13# If your app is served at a subpath (e.g. /app/), add: --base-href /app/14RUN flutter build web --release1516# Stage 2: Serve with Nginx alpine17FROM nginx:alpine AS runner1819# Remove default Nginx static files20RUN rm -rf /usr/share/nginx/html/*2122# Copy compiled Flutter web output from the builder stage23COPY --from=builder /app/build/web /usr/share/nginx/html2425# Add a simple Nginx config for Flutter SPA routing26# (all paths fall back to index.html so Flutter's router handles them)27RUN echo 'server { \28 listen 80; \29 root /usr/share/nginx/html; \30 index index.html; \31 location / { \32 try_files $uri $uri/ /index.html; \33 } \34}' > /etc/nginx/conf.d/default.conf3536EXPOSE 80Pro tip: Add a .dockerignore file at the project root listing build/, .dart_tool/, and .flutter-plugins to avoid copying those into the builder stage — it speeds up the docker build significantly.
Expected result: A Dockerfile exists at the root of your Flutter project alongside pubspec.yaml, containing the two-stage build and serve configuration.
Add a .dockerignore file to speed up the build
When Docker reads your project folder to build the image, it copies everything in the directory into the build context. Without a .dockerignore file, this includes generated directories that are large but unnecessary — the `build/` directory from previous local builds, the `.dart_tool/` cache, and `.flutter-plugins`. Including these wastes time and can cause the builder stage to use a cached local build instead of running a fresh `flutter build web` inside the container. Create a file named `.dockerignore` at the project root and add the entries below. Docker will skip these paths when building, making the `COPY . .` step in your Dockerfile faster. The `.dockerignore` syntax is similar to `.gitignore` — each line is a path or glob pattern relative to the project root. After adding this file, your `docker build` will be noticeably faster on subsequent runs because it only sends the source files Docker actually needs to the build daemon.
1# .dockerignore — exclude generated and local-only files from the Docker build context2build/3.dart_tool/4.flutter-plugins5.flutter-plugins-dependencies6.packages7.pub-cache/8.pub/9android/.gradle/10ios/Pods/11*.logPro tip: You can also add the android/ and ios/ directories to .dockerignore since the Docker build only targets web — this further reduces the build context size.
Expected result: A .dockerignore file exists at the project root. The next docker build sends a smaller context and completes faster.
Build the Docker image locally and verify it works
With the Dockerfile and .dockerignore in place, you can build the image. Open a terminal in your project root (the directory containing Dockerfile and pubspec.yaml) and run the docker build command. Give the image a tag so you can refer to it easily: use `-t my-app:latest` or a more specific name like `my-flutterflow-app:v1`. Docker will execute the two stages: first pulling the Flutter image (large, may take a few minutes on first download), running `flutter pub get`, and running `flutter build web --release` inside the builder container; then starting the Nginx stage, copying the compiled files, and applying the Nginx config. The build stage is the time-consuming part — Flutter web builds can take 2-5 minutes on a cold cache because the Dart-to-JavaScript compilation is heavyweight. After the image is built, run it with `docker run` to verify: map port 8080 on your machine to port 80 inside the container. Open a browser and navigate to `http://localhost:8080` — your FlutterFlow app should load in the browser. Test a few navigations to make sure the SPA routing works (navigate to a sub-screen, refresh the page — it should still load, not show an Nginx 404). If assets are missing or the app shows a blank screen, check the browser console for 404 errors on .js or .wasm files, which usually indicates a --base-href mismatch.
1# Build the Docker image (run this in the project root folder)2docker build -t my-flutterflow-app:latest .34# Run the container, mapping port 8080 on your machine to port 80 in the container5docker run -p 8080:80 my-flutterflow-app:latest67# Open http://localhost:8080 in your browser to verify the app loadsPro tip: If the browser shows a blank page with WASM errors in the console, add --web-renderer html to the flutter build web command in the Dockerfile: RUN flutter build web --release --web-renderer html. The HTML renderer has broader compatibility than the default CanvasKit/WASM renderer.
Expected result: The docker run command starts a container, and the FlutterFlow app loads correctly at http://localhost:8080. Navigation between screens works without 404 errors.
Push the image to a container registry for deployment or CI/CD
Once the image builds and runs correctly locally, tag it with a registry-qualified name and push it so it can be pulled by servers or CI/CD pipelines. The process differs by registry: for Docker Hub, your image tag is `your-dockerhub-username/my-flutterflow-app:latest`; for GitHub Container Registry, it's `ghcr.io/your-github-username/my-flutterflow-app:latest`; for GitLab Container Registry, it's `registry.gitlab.com/your-group/my-app:latest`. Log in to your registry in the terminal using `docker login`, then re-tag the image with the registry-qualified name using `docker tag`, and push with `docker push`. Once pushed, any server with Docker installed can pull and run your app with a single `docker run` command — no Flutter SDK, no build dependencies needed. For CI/CD integration, add the docker build and docker push steps to your pipeline (see the docker CI pipeline example in the code block below). Every FlutterFlow export that triggers a new GitHub commit can automatically trigger a CI build of a fresh Docker image — creating a seamless deploy pipeline from FlutterFlow visual editor to production container.
1# Tag the image for Docker Hub (replace 'yourusername' with your Docker Hub username)2docker tag my-flutterflow-app:latest yourusername/my-flutterflow-app:latest34# Log in to Docker Hub5docker login67# Push the image8docker push yourusername/my-flutterflow-app:latest910# --- On the deployment server ---11# Pull and run the image (no Flutter SDK needed on the server)12docker pull yourusername/my-flutterflow-app:latest13docker run -d -p 80:80 --name flutterflow-app yourusername/my-flutterflow-app:latestPro tip: Tag images with a version identifier (git commit SHA or a semantic version) in addition to 'latest' so you can roll back to a previous image if a new FlutterFlow export introduces a regression.
Expected result: The image is visible in your container registry. Running docker pull and docker run on a remote server starts the FlutterFlow web app without any Flutter SDK installed on that server.
Common use cases
Self-hosting the FlutterFlow web app on a VPS or cloud VM
You want to deploy your FlutterFlow web app to a DigitalOcean Droplet or AWS EC2 instance rather than using a managed hosting service. Build the Docker image from the exported Flutter project, push it to Docker Hub or a private registry, then pull and run it on the server with docker run -p 80:80. The Nginx container serves the Flutter web app to visitors just like any other website.
Build a Docker image of my FlutterFlow web app and run it on port 80 on a DigitalOcean Droplet using Nginx to serve the compiled Flutter web files.
Copy this prompt to try it in FlutterFlow
Running flutter build web in a GitLab or GitHub Actions CI pipeline
Your team doesn't want to maintain Flutter SDK installations on CI runners. Instead, the pipeline spins up the Flutter Docker image, builds the web app inside the container, and saves the build/web artifact for deployment. The build environment is identical every time — no SDK version drift between team members.
Create a GitLab CI job that uses the ghcr.io/cirruslabs/flutter Docker image to build flutter build web --release and upload the build/web folder as a pipeline artifact.
Copy this prompt to try it in FlutterFlow
Deploying to a Kubernetes cluster from the exported FlutterFlow codebase
Your organization runs Kubernetes for all deployments. After each FlutterFlow export to GitHub, a CI pipeline builds the Nginx Docker image, tags it with the git commit SHA, pushes it to a private container registry, and deploys it to the Kubernetes cluster by updating the image tag in the deployment manifest.
Build a Docker image of the FlutterFlow web app, tag it with the git commit SHA, push to our private registry, and update the Kubernetes deployment to roll out the new image.
Copy this prompt to try it in FlutterFlow
Troubleshooting
Flutter web app loads at / but navigating directly to /profile or refreshing on a sub-route shows an Nginx 404 page.
Cause: Flutter web uses client-side routing — all URL paths should serve index.html and let Flutter's router handle navigation. Without the SPA fallback in Nginx config, Nginx looks for a file at the requested path and returns 404 when it doesn't exist.
Solution: Ensure your Nginx config includes the `try_files $uri $uri/ /index.html;` directive inside the location / block. The Dockerfile in step 2 includes this configuration. If you're using a custom nginx.conf file, add this line and rebuild the image.
1location / {2 try_files $uri $uri/ /index.html;3}The Flutter app loads at the root URL but assets (images, fonts) return 404 when the app is served under a subpath like /app/.
Cause: Flutter web compiles absolute asset paths based on the --base-href flag. If you serve the app at /app/ but built with the default --base-href /, all asset URLs will be wrong.
Solution: Rebuild the Docker image with the --base-href flag set to match your deployment subpath. Edit the Dockerfile and change the flutter build line to `RUN flutter build web --release --base-href /app/`. Also update Nginx's root to handle the subpath, or use a reverse proxy prefix.
1RUN flutter build web --release --base-href /app/docker build fails with: "error: Cannot find 'pubspec.yaml'. No 'pubspec.yaml' file found."
Cause: Docker is building from the wrong directory, or the .dockerignore file accidentally excluded the source files, or the FlutterFlow export ZIP was extracted into a nested subfolder.
Solution: Confirm the Dockerfile and pubspec.yaml are in the same directory and that you run `docker build .` from that directory (the trailing period is the build context path). Check your .dockerignore file doesn't accidentally match `*.yaml` or `lib/`. If the ZIP extracted into a subdirectory like `my-app-export/my-app/`, navigate into the inner folder where pubspec.yaml lives before running docker build.
The Docker build runs out of memory with: "Killed" or the build stage hangs indefinitely on flutter build web.
Cause: Flutter web compilation is memory-intensive — the Dart-to-JavaScript transformation can require 2-4 GB of RAM. CI runners with small memory allocations (1-2 GB) frequently run out of memory.
Solution: Increase the memory limit of your Docker build environment or CI runner. In Docker Desktop, go to Settings → Resources and increase memory to at least 4 GB. On CI, request a runner with 4+ GB of RAM. Alternatively, run the flutter build web step outside Docker locally and use a simpler Dockerfile that just copies the pre-built build/web directory — though this means the Docker build is no longer self-contained.
Best practices
- Never bake Firebase config files (google-services.json), API keys, or any runtime secrets into the Docker image — Flutter web config is entirely client-visible; treat the image contents as public.
- Use multi-stage builds always — the Flutter SDK image is several gigabytes; the final Nginx image should be under 50 MB and contain only compiled files.
- Tag images with both a version identifier (git SHA or semantic version) and 'latest' so you can roll back to a previous working image when a new FlutterFlow export breaks something.
- Add a .dockerignore file to exclude build/, .dart_tool/, android/, and ios/ from the build context — this dramatically reduces context transfer time and avoids accidental stale cache use.
- Set --base-href correctly in the flutter build web command to match where Nginx will serve the app — a wrong base-href breaks all asset loading silently.
- Pin the Flutter Docker image to a specific version tag (e.g., ghcr.io/cirruslabs/flutter:3.22.0) in production CI rather than using :stable, to prevent unexpected Flutter SDK upgrades from breaking your build.
- For mobile CI (APK builds), Docker is the build environment but not the deployment vehicle — the APK artifact goes to Google Play, not to a running container.
- Use Nginx's gzip compression configuration to compress Flutter web's large .js and .wasm files — this significantly improves load time for users on slower connections.
Alternatives
GitLab CI natively uses Docker images for its runner environments, so you can run the flutter build web step inside the Flutter Docker image as a CI job without building a deployment Docker image — choose GitLab if CI is the goal, Docker if self-hosting is the goal.
DigitalOcean App Platform can deploy directly from a GitHub repository without Docker by detecting the Flutter web build — simpler than maintaining a Dockerfile if you don't need container-level control.
Terraform manages the cloud infrastructure that runs your Docker containers — use Terraform alongside Docker when you need infrastructure-as-code for the servers, networking, and registries hosting your FlutterFlow web app.
Frequently asked questions
Can I run the FlutterFlow editor itself inside a Docker container?
No. FlutterFlow is a hosted SaaS product — you use it through a browser at app.flutterflow.io. There is no self-hostable FlutterFlow server image to pull from Docker Hub. What you can containerize is the Flutter app that FlutterFlow generates for you, specifically the web target.
Does Dockerizing a FlutterFlow app work for iOS and Android?
For deployment, no — iOS and Android apps are distributed through the App Store and Google Play as binary files (.ipa/.apk), not as containers. Docker is useful for the CI build step (compiling the APK inside a Flutter Docker container on a Linux CI runner), but the final artifact goes to the app store, not to a running Docker container. Only the web target produces output (static HTML/JS/WASM) that makes sense to serve from a container.
How long does the Docker build take for a FlutterFlow web app?
Expect 3-8 minutes on the first build — mostly the flutter build web --release step, which does heavy Dart-to-JavaScript compilation. Subsequent builds are faster (1-3 minutes) because Docker caches the layer where packages are fetched (flutter pub get) as long as pubspec.yaml hasn't changed. Make sure .pub-cache is not in your .dockerignore if you want Docker to cache the pub layer properly.
Should I put any API keys in the Docker image?
No. Flutter web compiles to JavaScript that runs in the user's browser — everything in the compiled output is visible to anyone who opens DevTools. API keys, Firebase config, or any credentials embedded in the Flutter code are visible to users. For secrets, use a backend proxy (Firebase Cloud Functions or Supabase Edge Functions) that holds the secrets server-side and that your Flutter app calls at runtime. The Docker image itself contains only client code.
Can I use this Docker setup to let RapidDev help with deployment?
Yes — if you'd rather skip the Dockerfile and deployment pipeline setup, RapidDev's team handles FlutterFlow export-to-production workflows including Docker-based deployments every week. Reach out for a free scoping call at rapidevelopers.com/contact to discuss your hosting requirements.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation