Skip to content
Blog

Flutter for Desktop and Web: One Codebase Everywhere

Learn how to take one Flutter codebase and ship native apps to Windows, macOS, Linux, and the web alongside your mobile apps.

Published on August 17, 2026

AI Assistant

The pitch has always been “one codebase, every screen” — but for years the desktop and web versions felt like an afterthought. That changed. Flutter now compiles native Windows, macOS, and Linux apps from the same Dart code you write for mobile, and its web target can compile to both JavaScript and WebAssembly. Your models, state management, business logic, and most of your UI carry over untouched; only the platform-specific integration layer changes.

In this tutorial, you will learn how to add desktop and web targets to an existing Flutter project, run the app on each platform, and handle the differences that actually matter — input, window sizing, web routing, and plugins. Key technologies: Flutter SDK, Dart, and the flutter create --platforms workflow.

Prerequisites

  • Flutter 3.x installed and on your PATH
  • Desktop toolchain for at least one target (Visual Studio for Windows, Xcode for macOS, or a Linux toolchain with GTK)
  • A browser for the web target
  • An existing Flutter app (or create a fresh one with flutter create)

Core Content

Add desktop and web targets to an existing app

A default flutter create app includes Android and iOS. To add desktop and web support to an existing project, run:

flutter create --platforms=windows,macos,linux,web .

This generates the platform directories — windows/, macos/, linux/, and web/ — alongside your existing android/ and ios/ folders. To add only a subset, list just those platforms.

Run on each platform

The flutter run -d <device> command targets a specific platform:

# Windows desktop
flutter run -d windows

# macOS desktop
flutter run -d macos

# Linux desktop
flutter run -d linux

# Web (defaults to the Chrome device)
flutter run -d chrome

If you omit -d, Flutter lists the available devices. The same hot reload workflow you use on mobile works on desktop and web — edit, save, and the UI updates instantly.

Handle window sizing on desktop

Desktop windows don’t have a fixed screen size, so you often want to set a minimum and initial window size. In linux/my_application.cc and windows/runner/main.cpp you can adjust the native window, but a simpler cross-platform approach is the window_manager package:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await windowManager.ensureInitialized();
  await windowManager.setMinimumSize(const Size(800, 600));
  await windowManager.setTitle('My Desktop App');
  runApp(const MyApp());
}

For the web target, layout is inherently responsive — use LayoutBuilder, MediaQuery, and adaptive widgets to scale from a phone window to a full browser tab.

Desktop keyboard shortcuts and menus

Desktop users expect keyboard shortcuts and menu bars. Flutter supports the Shortcuts and Actions widgets for key handling:

Shortcuts(
  shortcuts: const {
    SingleActivator(LogicalKeyboardKey.keyO, control: true): OpenFileIntent(),
  },
  child: Actions(
    actions: {
      OpenFileIntent: CallbackAction<OpenFileIntent>(
        onInvoke: (_) => openFileDialog(),
      ),
    },
    child: const FileEditor(),
  ),
)

For native menu bars, use MenuBar (or a platform plugin) — on macOS this integrates with the system menu; on Windows and Linux it renders as an in-app menu.

Web URL strategies and routing

The web target uses flutter_web_plugins for routing. By default web apps use hash-based URLs (/#/about), which work everywhere without server configuration. For clean paths (/about) you use the PathUrlStrategy:

import 'package:flutter_web_plugins/url_strategy.dart';

void main() {
  usePathUrlStrategy();
  runApp(const MyApp());
}

When using path URLs, configure your web host to serve index.html for unknown routes so deep links resolve to the app.

Check plugin support

Most Flutter plugins are now federated and cover desktop and web. Before relying on one, verify its platform support on pub.dev — each plugin lists the platforms it implements. For platform-specific code that lacks a plugin, use conditional imports or the dart:io vs dart:html split.

Putting It All Together

A complete project demonstrates the pattern: one lib/ directory with shared logic and UI, platform directories for each native target, and adaptive code paths where the platforms genuinely differ. Build release binaries per platform:

flutter build windows
flutter build macos
flutter build linux
flutter build web --wasm   # optional: compile to WebAssembly

Each command emits an installable artifact — an .exe, .app, .AppImage/.deb, or a deployable web bundle — all from the same source.

Conclusion & Next Steps

You’ve added desktop and web targets to a Flutter app, learned to run and release on each, and handled the real differences: window management, keyboard input, routing, and plugin availability. The mobile codebase is now a full cross-platform codebase.

Next Steps: explore flutter build web --wasm for WebAssembly performance, add app flavors for per-platform configuration, and study the adaptive and responsive design guidance for large screens and foldables.

References: