Flutter Project Setup That Scales in 2025

Flutter

A smart Flutter project setup saves hours on every feature, release, and handoff. This guide shows a pragmatic scaffold you can adopt today—folders, flavors, env management, lints, tests, and CI—so your app scales without chaos.

Audience: BeginnerTested on: Flutter 3.x, Dart 3.x, macOS 14 / Windows 11, Android 14 / iOS 17

Goals

  • One codebase → multiple environments (dev/qa/prod) with reproducible builds.
  • Clear folders, predictable naming, and opinionated tooling.
  • Quality gates (lints/tests) that won’t slow you down.

Recommended folder structure

lib/
  app/                # app root, router, themes, di
  features/
    auth/
      data/           # repositories, data sources
      domain/         # entities/use-cases
      presentation/   # widgets, state
  shared/             # ui kit, utils, services (logger, http, storage)
assets/
  images/  fonts/  lottie/
tool/
  analysis_options.yaml
  env/                # dev.json, qa.json, prod.json (non-secret)
test/  integration_test/

Flavors & environment config

Keep secrets out of source control. Use --dart-define for non-secret config and platform keystores/Keychain for secrets.

# tool/env/dev.json (example; non-secret)
{
  "API_BASE_URL": "https://api-dev.example.com",
  "FEATURE_FLAGS": "new_ui=true"
}
# Build commands
flutter run --dart-define-from-file=tool/env/dev.json
flutter build apk --release --dart-define-from-file=tool/env/qa.json
flutter build appbundle --release --dart-define-from-file=tool/env/prod.json

iOS/Android “flavors” are optional; many teams simply pass --dart-define-from-file and switch icons/splash via config.

Dependency basics (keep it lean)

  • HTTP: http or dio (choose one). Wrap with a small client for timeouts/retries.
  • State: Start simple (Provider/Riverpod). Avoid premature architecture bloat.
  • Storage: shared_preferences for simple, hive for structured, flutter_secure_storage for secrets.
  • Logging: logger with release-safe filtering and redaction.

Lints you’ll actually keep

Create tool/analysis_options.yaml and include it from the root to share across packages.

# analysis_options.yaml
include: package:flutter_lints/flutter.yaml

analyzer:
  language:
    strict-inference: true
    strict-casts: true
linter:
  rules:
    always_declare_return_types: true
    prefer_final_locals: true
    prefer_const_constructors: true
    avoid_print: true
# Run
dart analyze

Testing: fast feedback

# Unit & widget tests
flutter test

# Integration (smoke) on device/emulator
flutter drive --profile -t integration_test/smoke_test.dart

Golden tests? Pin fonts/themes to avoid flakiness and store baselines under test/goldens.

Release hardening

# Smaller, debuggable releases
flutter build appbundle --release \
  --obfuscate --split-debug-info=out/symbols/$(date +%Y-%m-%d_%H%M%S) \
  --dart-define-from-file=tool/env/prod.json
  • Keep symbol files for crash mapping.
  • Automate icons (flutter_launcher_icons) and splash (flutter_native_splash).

CI outline (GitHub Actions example)

- name: Setup Flutter
  uses: subosito/flutter-action@v2
  with:
    flutter-version: 'stable'

- name: Get deps & analyze
  run: |
    flutter pub get
    dart analyze --fatal-infos --fatal-warnings

- name: Tests
  run: flutter test --coverage

- name: Build QA APK
  run: flutter build apk --release --split-per-abi \
       --dart-define-from-file=tool/env/qa.json

- name: Build Play AAB
  run: flutter build appbundle --release \
       --dart-define-from-file=tool/env/prod.json \
       --obfuscate --split-debug-info=out/symbols/${{ github.run_id }}

Security & pitfalls

  • Secrets in git: Never store keys in JSON or code. Use CI secrets & platform keystores.
  • Multiple env drifts: Keep one source of truth (the JSON). Don’t fork code per env.
  • Measuring in debug: Validate performance in profile/release, not debug.

FAQ

Q: Do I need flavors for everything?
A: Not necessarily. Many teams ship with plain targets and --dart-define-from-file for speed.

Q: Where do I put big one-off scripts?
A: In tool/ with README comments and a Makefile/PowerShell shim if desired.

Conclusion

Start with a lean folder layout, pass environment values via --dart-define, enforce lints/tests, and script your builds. This Flutter project setup scales from the first commit to production without rewrites.

https://docs.flutter.dev/deployment
https://docs.flutter.dev/testing
https://dart.dev/tools/linter-rules

Updated: 2025-10-26

Comment

Copied title and URL