Flutter Lesson 4 of 83 2 min read
Flutter Project Structure Explained
Understand the folders and files in a Flutter project: lib, pubspec.yaml, android, ios, web and test, and how to organise your own code.
On this page
flutter create makes many files. You will work in only a few of them.
The folders #
my_first_app/
lib/ # your Dart code
main.dart # the app starts here
test/ # automated tests
android/ # the native Android project
ios/ # the native iOS project
web/ # files for the web build
windows/ macos/ linux/ # desktop projects
build/ # generated output
.dart_tool/ # tool cache
pubspec.yaml # name, packages, assets, fonts
pubspec.lock # exact package versions
analysis_options.yaml # lint rules
| Path | How often you touch it |
|---|---|
lib/ | All the time. This is the app |
pubspec.yaml | When you add a package, an image or a font |
test/ | When you write tests |
android/, ios/ | Sometimes: app name, icon, permissions, signing |
web/, desktop folders | Rarely |
build/, .dart_tool/ | Never. They are regenerated |
pubspec.yaml #
name: my_first_app
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ^3.5.0
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter:
uses-material-design: true
assets:
- assets/images/
version: 1.0.0+1is the version users see, then a plus, then the build number that app stores require to go up with each upload.- Images and other files must be listed under
assetsbefore the app can load them. - YAML depends on indentation. Use two spaces, never tabs.
Organising lib as the app grows #
Do not keep everything in main.dart. Grouping by feature scales well:
lib/
main.dart
app.dart # MaterialApp, theme, routes
features/
auth/
login_page.dart
auth_service.dart
products/
product.dart
product_list_page.dart
product_api.dart
shared/
widgets/
primary_button.dart
utils/
formatters.dart
Everything about products sits together, so a change to that feature touches one folder. The architecture chapter goes deeper.
Where native settings live #
| Task | Android | iOS |
|---|---|---|
| App name | android/app/src/main/AndroidManifest.xml | ios/Runner/Info.plist |
| Permissions | AndroidManifest.xml | Info.plist |
| App id, minimum OS version | android/app/build.gradle.kts | Xcode project settings |
| Launcher icon | android/app/src/main/res/ | ios/Runner/Assets.xcassets/ |
Version control #
Commit lib/, test/, the platform folders, pubspec.yaml, pubspec.lock and analysis_options.yaml. Leave out build/ and .dart_tool/. The generated .gitignore already does this.
Try it yourself #
Move CounterPage from the previous lesson into lib/features/counter/counter_page.dart and import it in main.dart.