Project Structure
Understand the folder structure of a Flutter project.
What is it?
A Flutter project structure is the organized layout of folders and files that make up a Flutter application. It includes configuration files, platform-specific folders, source code, and assets. Understanding this structure is essential for navigating and maintaining Flutter projects.
Why does it exist?
Project structure exists to:
- Organize code in a predictable way
- Separate platform-specific code
- Manage dependencies and configurations
- Store assets like images and fonts
- Support different build environments
- Enable tooling and build systems
- Maintain consistency across projects
Root Directory Structure
The root directory contains configuration files and the main folders for your Flutter app.
my_flutter_app/
├── android/ # Android platform-specific code
├── ios/ # iOS platform-specific code
├── lib/ # Main source code (Dart files)
├── test/ # Unit and widget tests
├── web/ # Web platform-specific code
├── windows/ # Windows platform-specific code
├── macos/ # macOS platform-specific code
├── linux/ # Linux platform-specific code
├── build/ # Generated build output
├── .dart_tool/ # Dart tool cache
├── .idea/ # IDE configuration (Android Studio)
├── .vscode/ # VS Code configuration
├── pubspec.yaml # Project dependencies and metadata
├── pubspec.lock # Locked dependency versions
├── README.md # Project documentation
├── CHANGELOG.md # Version history
├── analysis_options.yaml # Dart linter rules
└── .gitignore # Git ignore rules
What's happening here?
- Platform folders contain native code for each platform
- lib/ is where all Dart code lives
- pubspec.yaml is the most important configuration file
- build/ is generated and should be ignored in git
- Platform folders are auto-generated by Flutter
lib Folder
The
lib/folder is where all your Dart source code goes.
lib/
├── main.dart # Entry point of the application
├── models/ # Data models
│ ├── user.dart
│ └── product.dart
├── screens/ # Full screen widgets
│ ├── home_screen.dart
│ ├── login_screen.dart
│ └── profile_screen.dart
├── widgets/ # Reusable widgets
│ ├── custom_button.dart
│ └── loading_indicator.dart
├── services/ # Business logic and API calls
│ ├── api_service.dart
│ └── auth_service.dart
├── utils/ # Helper functions and constants
│ ├── constants.dart
│ └── validators.dart
├── providers/ # State management
│ ├── auth_provider.dart
│ └── theme_provider.dart
└── config/ # App configuration
├── routes.dart
└── themes.dart
What's happening here?
- main.dart is the entry point with main() function
- Organize by feature or type (models, screens, widgets)
- Keep business logic separate from UI
- Use clear naming conventions
- Folder structure can be customized
pubspec.yaml
The
pubspec.yamlfile defines your project's metadata, dependencies, and assets.
name: my_flutter_app
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
# UI and styling
cupertino_icons: ^1.0.6
google_fonts: ^5.0.0
# State management
provider: ^6.0.0
# Networking
http: ^1.1.0
# Local storage
shared_preferences: ^2.2.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
uses-material-design: true
# Assets
assets:
- assets/images/
- assets/fonts/
- assets/config.json
# Fonts
fonts:
- family: CustomFont
fonts:
- asset: assets/fonts/CustomFont-Regular.ttf
- asset: assets/fonts/CustomFont-Bold.ttf
weight: 700
What's happening here?
- name and version identify your package
- dependencies are packages your app needs
- dev_dependencies are only needed during development
- flutter: section configures assets and fonts
- Version constraints use semantic versioning
Android Folder
The
android/folder contains Android-specific configuration and code.
android/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/ # Java/Kotlin code
│ │ │ ├── kotlin/ # Kotlin code (modern)
│ │ │ ├── res/ # Resources (images, layouts)
│ │ │ └── AndroidManifest.xml # App manifest
│ │ ├── debug/
│ │ └── profile/
│ ├── build.gradle # App-level build config
│ └── proguard-rules.pro # Code obfuscation
├── gradle/
│ └── wrapper/
│ └── gradle-wrapper.properties
├── build.gradle # Project-level build config
├── settings.gradle # Project settings
├── gradle.properties # Gradle properties
├── gradlew # Gradle wrapper (Unix)
├── gradlew.bat # Gradle wrapper (Windows)
└── local.properties # Local machine settings (ignored)
What's happening here?
- Contains Android-specific build configuration
- AndroidManifest.xml defines app permissions and activities
- res/ contains Android-specific resources
- build.gradle files control the build process
- local.properties stores local SDK path
iOS Folder
The
ios/folder contains iOS-specific configuration and code.
ios/
├── Runner/
│ ├── AppDelegate.swift # App delegate
│ ├── GeneratedPluginRegistrant.m # Plugin registration
│ ├── GoogleService-Info.plist # Firebase config
│ ├── Info.plist # App info and permissions
│ ├── Assets.xcassets/ # App icons and assets
│ └── Base.lproj/
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Flutter/
│ ├── Generated.xcconfig # Generated build config
│ └── Debug.xcconfig # Debug build config
├── Podfile # CocoaPods dependencies
├── Podfile.lock # Locked pods
├── Runner.xcworkspace # Xcode workspace
├── Runner.xcodeproj # Xcode project
└── Pods/ # Installed pods (ignored)
What's happening here?
- Contains iOS-specific build configuration
- Runner/ contains the iOS app target
- Info.plist defines app permissions
- Podfile manages CocoaPods dependencies
- Opens with .xcworkspace in Xcode
Web Folder
The
web/folder contains web-specific configuration.
web/
├── index.html # Main HTML entry
├── manifest.json # PWA manifest
├── favicon.png # App icon
├── icons/ # App icons
│ ├── Icon-192.png
│ └── Icon-512.png
└── assets/
└── fonts/ # Web fonts
What's happening here?
- index.html is the web entry point
- manifest.json enables progressive web app features
- Icons support different display sizes
- Can be customized for specific web needs
Test Folder
The
test/folder contains unit and widget tests.
test/
├── unit/ # Unit tests
│ ├── models_test.dart
│ └── services_test.dart
├── widget/ # Widget tests
│ ├── home_screen_test.dart
│ └── custom_button_test.dart
├── integration/ # Integration tests
│ ├── app_test.dart
│ └── navigation_test.dart
└── test_helper.dart # Test utilities
What's happening here? - Unit tests test individual functions and classes - Widget tests test UI components - Integration tests test full app flows - Tests should mirror your lib folder structure
Build Folder
The
build/folder contains generated output and should not be modified manually.
build/
├── app/ # App-specific build output
├── ios/ # iOS build output
├── android/ # Android build output
├── web/ # Web build output
├── windows/ # Windows build output
├── macos/ # macOS build output
└── linux/ # Linux build output
What's happening here?
- Contains compiled app files
- Generated by Flutter build system
- Should be ignored in .gitignore
- Can be deleted and regenerated
- Clean with flutter clean
Common Customizations
Feature-Based Organization
lib/
├── features/
│ ├── auth/
│ │ ├── models/
│ │ ├── screens/
│ │ ├── widgets/
│ │ └── services/
│ ├── home/
│ │ ├── models/
│ │ ├── screens/
│ │ └── widgets/
│ └── profile/
│ ├── models/
│ ├── screens/
│ └── widgets/
├── core/
│ ├── utils/
│ ├── constants/
│ └── themes/
└── main.dart
Clean Architecture
lib/
├── data/
│ ├── datasources/
│ ├── models/
│ └── repositories/
├── domain/
│ ├── entities/
│ ├── usecases/
│ └── repositories/
├── presentation/
│ ├── blocs/
│ ├── screens/
│ └── widgets/
└── main.dart
Best Practices
- Keep
main.dartminimal - use it only for app setup - Organize code by features, not by type
- Use clear and consistent naming conventions
- Keep platform-specific code in respective folders
- Use
pubspec.yamlto manage dependencies - Keep
lib/organized and clean - Use
analysis_options.yamlfor lint rules
Common Mistakes
Putting Everything in main.dart
Wrong:
// All code in one file
void main() { ... }
class HomeScreen { ... }
class UserModel { ... }
class ApiService { ... }
Correct:
lib/
├── main.dart
├── screens/
├── models/
└── services/
Ignoring pubspec.lock
Wrong:
# Not committing pubspec.lock
Correct:
# Commit pubspec.lock to ensure consistent builds
# It locks dependency versions across team members
Placing Assets Wrong
Wrong:
lib/assets/images/logo.png # Assets in lib folder
Correct:
assets/images/logo.png # Assets outside lib
Summary
A Flutter project has a well-defined structure with lib/ for Dart code, platform-specific folders for native code, and configuration files like pubspec.yaml. Understanding this structure helps you organize code effectively and navigate projects with ease.
Next Steps
Did You Know?
- You can create projects with
flutter create -tfor templates - Flutter generates platform folders automatically
- You can use
flutter cleanto delete build directory pubspec.yamlsupports path dependencies for local packages- The
build/folder can be 100MB+ for large projects - Flutter supports custom project templates