FlutterFever Studio
Back to packages

Ngrok Flutter package guide

FFI‑based plugin that creates secure ngrok tunnels from Flutter apps on mobile and desktop.

Install command
Copy and run in your Flutter project
flutter pub add ngrok_flutter

When to use Ngrok Flutter

Ngrok Flutter brings the power of ngrok’s public tunneling service directly into your Flutter codebase. By leveraging Dart's foreign function interface (FFI), the plugin embeds the native ngrok binary for Android, iOS, macOS, Windows, and Linux, allowing you to spin up authenticated tunnels without leaving the Flutter environment. This eliminates the need for external scripts, separate terminal windows, or manual port forwarding during development and testing. The tunnel runs in the same process as your app, giving you full control over its lifecycle, authentication token, and region selection through simple Dart APIs.

The primary use‑case for Ngrok Flutter is to expose a locally running development server—whether it’s a REST API, a WebSocket endpoint, or a gRPC service—to the internet with a single line of code. This is especially valuable when testing push notifications, deep links, or third‑party integrations that require a publicly reachable URL. Because the plugin works on both mobile and desktop platforms, you can develop a single code path that works on an Android phone, an iOS device, or a Windows laptop, making cross‑platform debugging far more efficient.

In a typical Flutter architecture, Ngrok Flutter sits at the networking layer, often wrapped by a repository or service class that abstracts tunnel management from UI code. For example, a `TunnelService` can expose `startTunnel()` and `stopTunnel()` methods that internally call the plugin, while the UI listens to a `Stream` of tunnel status events. This separation keeps your state management solution—whether Provider, Riverpod, Bloc, or GetX—clean and focused on business logic. The plugin does not interfere with existing HTTP clients like `http` or `dio`; instead, it provides a public URL that those clients can target, making integration seamless.

Getting Ngrok Flutter up and running is straightforward. After adding the dependency with `flutter pub add ngrok_flutter`, you must supply your ngrok authtoken, which you can obtain from the ngrok dashboard. The plugin automatically downloads the appropriate native binary for the current platform on first use, but you can also bundle the binaries yourself for offline builds. Once initialized, calling `Ngrok.startTunnel(port: 8080, region: 'us')` returns a `Future<String>` containing the public URL. The tunnel can be stopped with `Ngrok.stopTunnel()`, and you can query its status via `Ngrok.isRunning`. All calls are asynchronous and safe to invoke from the UI thread.

While Ngrok Flutter is a powerful development tool, there are production considerations to keep in mind. Running a persistent tunnel from a production app can expose your backend to unwanted traffic and increase latency. It is recommended to enable tunnels only in debug or staging builds, and to enforce strict authentication on the exposed endpoint. Additionally, because the plugin relies on native binaries, you should test the final app on each target platform to verify that the correct binary is bundled and that the required permissions (e.g., network access) are declared in the platform-specific manifest files. Monitoring the tunnel’s health and handling unexpected disconnects gracefully will improve the end‑user experience.

For beginners, a simple example might involve creating a local Express server that serves mock data, then using Ngrok Flutter to expose it while testing a mobile app that consumes the API. The same code works on a desktop Flutter app, allowing you to share a single development environment across the whole team. As you grow more comfortable, you can integrate the tunnel lifecycle into your CI/CD pipeline, automatically starting a tunnel for integration tests that require external callbacks. Overall, Ngrok Flutter reduces friction, accelerates feedback loops, and keeps your Flutter projects truly cross‑platform.

expose local API to external services during development
test webhook integrations on mobile devices
share a preview of a desktop app with remote collaborators
run end‑to‑end tests that require a public callback URL
debug deep links and push notifications without a cloud server

Pros

  • single codebase for iOS, Android, macOS, Windows, Linux
  • no external CLI required during development
  • asynchronous Dart API fits Flutter's reactive model
  • supports custom regions and authtoken authentication
  • lightweight wrapper around official ngrok binary

Watch outs

  • adds native binary size to the app bundle
  • not suitable for production‑grade public exposure
  • requires internet access on first launch to download binaries
  • FFI means it cannot run on Flutter Web

Setup notes

1. Add the dependency: `flutter pub add ngrok_flutter`. 2. Run `flutter pub get`. 3. Obtain an ngrok authtoken from https://dashboard.ngrok.com and add it to your app (e.g., via environment variable or secure storage). 4. Initialize the plugin early, e.g., in `main()`: ```dart await Ngrok.initialize(authToken: const String.fromEnvironment('NGROK_TOKEN')); ``` 5. On first launch the plugin will download the native binary for the current platform. Ensure the device has internet access. 6. For iOS and Android, add the required network permissions to `Info.plist` and `AndroidManifest.xml` respectively. 7. Test the tunnel with `final url = await Ngrok.startTunnel(port: 8080);` and verify the returned URL works in a browser. 8. Remember to stop the tunnel with `await Ngrok.stopTunnel();` when the app is disposed or in production builds.

Supported on Android (API 21+), iOS (13+), macOS (Intel & Apple Silicon), Windows (10+), and Linux (glibc). Requires Dart 2.19+ and Flutter 3.10+. The plugin uses FFI, so it is not compatible with Flutter Web. Ensure the target device architecture matches one of the bundled binaries (arm64, x86_64).

import 'package:flutter/material.dart';
import 'package:ngrok_flutter/ngrok_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Ngrok.initialize(authToken: 'YOUR_NGROK_AUTHTOKEN');
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _tunnelUrl = 'Not started';

  Future<void> _startTunnel() async {
    final url = await Ngrok.startTunnel(port: 8080, region: 'us');
    setState(() => _tunnelUrl = url);
  }

  Future<void> _stopTunnel() async {
    await Ngrok.stopTunnel();
    setState(() => _tunnelUrl = 'Stopped');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Ngrok Flutter Demo')),
        body: Center(
          child: Column(mainAxisSize: MainAxisSize.min, children: [
            Text('Tunnel URL: $_tunnelUrl'),
            const SizedBox(height: 20),
            ElevatedButton(onPressed: _startTunnel, child: const Text('Start Tunnel')),
            ElevatedButton(onPressed: _stopTunnel, child: const Text('Stop Tunnel')),
          ]),
        ),
      ),
    );
  }
}

Official package resources