"Most beginners open a Flutter project and feel overwhelmed by the file structure. Once you understand what each folder does, it becomes the most logical layout you've ever seen."

The Complete Flutter Project Structure

When you run flutter create my_app, this is what you get:

my_app/
├── android/          ← Android-specific native code
├── ios/              ← iOS-specific native code
├── lib/              ← YOUR Flutter/Dart code lives here
│   └── main.dart     ← Entry point of the app
├── test/             ← Automated tests
├── web/              ← Web platform files (if enabled)
├── windows/          ← Windows desktop files (if enabled)
├── assets/           ← Images, fonts, JSON files (you create this)
├── pubspec.yaml      ← Project config + dependencies
├── pubspec.lock      ← Auto-generated, exact dependency versions
├── README.md         ← Documentation
└── .gitignore        ← Git ignore rules

The rule is simple: you spend 95% of your time in lib/ and pubspec.yaml. Everything else you rarely touch.

The lib/ Folder — Where Your Code Lives

The lib/ folder is your entire Flutter application. Everything you build goes here.

lib/main.dart — The Entry Point

Every Flutter app starts from main.dart. The main() function is the first thing that runs:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());  // This launches your app
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
      ),
      home: const HomePage(),  // First screen
    );
  }
}

Recommended lib/ folder structure for real apps

lib/
├── main.dart
├── screens/          ← Full-page screens (HomeScreen, ProfileScreen)
│   ├── home_screen.dart
│   └── profile_screen.dart
├── widgets/          ← Reusable UI components
│   ├── topic_card.dart
│   └── custom_button.dart
├── models/           ← Data classes (Topic, User, etc.)
│   └── topic.dart
├── services/         ← API calls, database, Firebase
│   └── api_service.dart
├── utils/            ← Helper functions, constants
│   └── constants.dart
└── theme/            ← App colours, typography
    └── app_theme.dart
💡 Naming Convention Flutter files use snake_case (underscores): home_screen.dart, not HomeScreen.dart. Classes inside use PascalCase: class HomeScreen. This is a Dart convention — follow it consistently.

pubspec.yaml — The Most Important Config File

pubspec.yaml is Flutter's configuration file. It controls the app name, version, dependencies (packages), and assets. Think of it like package.json in Node.js or .csproj in .NET.

name: my_app                    # App package name (no spaces, lowercase)
description: A new Flutter app. # Short description
version: 1.0.0+1                # Version: 1.0.0 is display version, +1 is build number

environment:
  sdk: '>=3.0.0 <4.0.0'        # Dart SDK version constraint

dependencies:
  flutter:
    sdk: flutter                # Core Flutter framework (always here)

  # Add packages here:
  http: ^1.1.0                  # HTTP requests
  shared_preferences: ^2.2.0   # Local storage
  google_fonts: ^6.1.0          # Custom fonts from Google

dev_dependencies:
  flutter_test:
    sdk: flutter                # Testing framework
  flutter_lints: ^3.0.0        # Code linting rules

flutter:
  uses-material-design: true    # Enables Material icons

  # Assets — tell Flutter about your image/font files
  assets:
    - assets/images/            # All files in this folder
    - assets/images/logo.png    # Or specific files
    - assets/data/topics.json  # JSON files

  fonts:
    - family: Poppins
      fonts:
        - asset: assets/fonts/Poppins-Regular.ttf
        - asset: assets/fonts/Poppins-Bold.ttf
          weight: 700
⚠️ YAML indentation is critical YAML uses spaces (not tabs) for indentation. One wrong indentation breaks the entire file. VS Code with the Flutter extension highlights YAML errors in real time.

How to Add a Package (Dependency)

Flutter has thousands of free packages at pub.dev. Adding one is a two-step process:

Step 1 — Add to pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  http: ^1.1.0          # Add this line

Step 2 — Run pub get

flutter pub get

This downloads the package and makes it available in your code. VS Code runs this automatically when you save pubspec.yaml.

Step 3 — Import and use

import 'package:http/http.dart' as http;

final response = await http.get(Uri.parse('https://api.example.com/data'));

The ^ version prefix

^1.1.0 means "version 1.1.0 or higher, but less than 2.0.0". This allows minor updates but prevents breaking changes from major versions. Always use ^ unless you have a specific reason not to.

The assets/ Folder

Images, fonts, and data files go in the assets/ folder. You create this folder yourself — it doesn't exist by default.

Creating and using assets

# Create these folders in your project root:
assets/
├── images/
│   ├── logo.png
│   └── banner.jpg
├── fonts/
│   └── CustomFont-Regular.ttf
└── data/
    └── topics.json

Then declare them in pubspec.yaml (as shown above), then use in code:

// Image from assets
Image.asset('assets/images/logo.png')

// Image with specific size
Image.asset(
  'assets/images/banner.jpg',
  width: 300,
  height: 200,
  fit: BoxFit.cover,
)

// JSON from assets
import 'package:flutter/services.dart';

Future<String> loadJson() async {
  return await rootBundle.loadString('assets/data/topics.json');
}

The android/ and ios/ Folders

These contain platform-specific native code. You rarely need to edit these directly, but knowing what they contain helps when you encounter native configuration tasks.

android/

  • android/app/build.gradle — Android build configuration: min SDK version, target SDK, app ID
  • android/app/src/main/AndroidManifest.xml — App permissions (internet, camera, location)
  • android/app/src/main/res/ — App icon files for different screen densities

ios/

  • ios/Runner/Info.plist — iOS app configuration: permissions, app name, bundle ID
  • ios/Runner/Assets.xcassets/ — iOS app icons and launch images
📌 When to edit these You edit android/ios files when: changing app permissions, updating the app icon, changing the bundle ID/package name, or integrating native SDKs (like Firebase or Google Maps).

The test/ Folder

Flutter comes with a testing framework built in. The test/ folder contains automated tests for your app.

// test/widget_test.dart — the default test file
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/main.dart';

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    await tester.pumpWidget(const MyApp());
    expect(find.text('0'), findsOneWidget);
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();
    expect(find.text('1'), findsOneWidget);
  });
}

Run tests with: flutter test

Flutter Project Structure — Quick Reference

  • lib/ — All your Dart/Flutter code. This is where you spend your time.
  • lib/main.dart — Entry point. Contains main() and root MaterialApp.
  • pubspec.yaml — Config file. Add packages, declare assets, set app version.
  • assets/ — Images, fonts, JSON. Create it yourself, declare in pubspec.yaml.
  • android/ — Android native config. Edit for permissions and app icon.
  • ios/ — iOS native config. Edit for permissions and app icon.
  • test/ — Automated tests. Write tests here, run with flutter test.
  • pubspec.lock — Auto-generated. Commit to Git. Never edit manually.