Clean Architecture Flutter Project Setup Guide ๐Ÿš€

This is a complete, stepโ€‘byโ€‘step guide that collects all the pieces of our Clean Architecture Flutter project. This document is designed to help our team set up the project with theming, responsiveness, localization (using easy_localization), state management (BLoC & Provider), and automation scriptsโ€”all while maintaining code quality with strict linter rules and Git hooks. Enjoy the ride! ๐Ÿš€
 

Table of Contents

  1. Project Overview & Folder Structure ๐Ÿ—‚
  2. Dependencies & pubspec.yaml Setup ๐Ÿ“ฆ
  3. Core Modules Setup ๐Ÿ› 
  4. Main Application Setup (main.dart) ๐ŸŽฏ
  5. Sample Home Screen (home_screen.dart) ๐Ÿ“ฑ
  6. Module Scaffolding Shell Script โš™๏ธ
  7. Git Hooks & Linter Configuration ๐Ÿ”’
  8. Final Thoughts ๐ŸŒŸ

 

1. Project Overview & Folder Structure ๐Ÿ—‚

Our project is structured according to Clean Architecture principles. Each feature has its own sub-folders for data, domain, and presentation layers. Additionally, we have a core folder for shared utilities such as theme, responsiveness, and localization.

my_flutter_app/
โ”œโ”€โ”€ assets/
โ”‚   โ””โ”€โ”€ translations/
โ”‚       โ”œโ”€โ”€ en.json
โ”‚       โ””โ”€โ”€ es.json
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ”œโ”€โ”€ responsive/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ responsive.dart
โ”‚   โ”‚   โ”œโ”€โ”€ theme/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ app_theme.dart
โ”‚   โ”‚   โ””โ”€โ”€ utils/
โ”‚   โ”œโ”€โ”€ features/
โ”‚   โ”‚   โ””โ”€โ”€ feature_name/           # Replace with your module/feature name
โ”‚   โ”‚       โ”œโ”€โ”€ data/
โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ datasources/
โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ models/
โ”‚   โ”‚       โ”‚   โ””โ”€โ”€ repositories/
โ”‚   โ”‚       โ”œโ”€โ”€ domain/
โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ entities/
โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ repositories/
โ”‚   โ”‚       โ”‚   โ””โ”€โ”€ usecases/
โ”‚   โ”‚       โ””โ”€โ”€ presentation/
โ”‚   โ”‚           โ”œโ”€โ”€ screens/
โ”‚   โ”‚           โ”‚   โ””โ”€โ”€ home_screen.dart
โ”‚   โ”‚           โ”œโ”€โ”€ widgets/
โ”‚   โ”‚           โ”œโ”€โ”€ bloc/         # For BLoC-based state management
โ”‚   โ”‚           โ””โ”€โ”€ provider/     # For Provider-based state management
โ”‚   โ””โ”€โ”€ main.dart
โ”œโ”€โ”€ analysis_options.yaml
โ””โ”€โ”€ setup_project.sh              # Shell script to scaffold folders & files

 

2. Dependencies & pubspec.yaml Setup ๐Ÿ“ฆ

Update your pubspec.yaml to include the necessary dependencies:

name: my_flutter_app
description: A Flutter app using Clean Architecture with easy_localization.

environment:
  sdk: ">=2.17.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  easy_localization: ^3.0.0
  flutter_bloc: ^8.0.0    # (Optional: For BLoC state management)
  provider: ^6.0.0        # (Optional: For Provider state management)

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true

  # Specify the directory for your translation files
  assets:
    - assets/translations/

 

3. Core Modules Setup ๐Ÿ› 

Theme (app_theme.dart) ๐ŸŽจ

Create lib/core/theme/app_theme.dart with the following content:

import 'package:flutter/material.dart';

class AppTheme {
  /// Returns the light theme configuration.
  static ThemeData lightTheme() {
    return ThemeData(
      primarySwatch: Colors.blue,
      brightness: Brightness.light,
      visualDensity: VisualDensity.adaptivePlatformDensity,
      // Add additional light theme settings (fonts, icon themes, etc.)
    );
  }

  /// Returns the dark theme configuration.
  static ThemeData darkTheme() {
    return ThemeData(
      primarySwatch: Colors.blue,
      brightness: Brightness.dark,
      visualDensity: VisualDensity.adaptivePlatformDensity,
      // Add additional dark theme settings
    );
  }
}

 

Responsive (responsive.dart) ๐Ÿ“

Create lib/core/responsive/responsive.dart with the following content:

import 'package:flutter/material.dart';

class Responsive {
  final BuildContext context;
  Responsive(this.context);

  /// Returns the screen width.
  double get width => MediaQuery.of(context).size.width;

  /// Returns the screen height.
  double get height => MediaQuery.of(context).size.height;

  /// Returns true if the device is mobile (width < 600).
  bool get isMobile => width < 600;

  /// Returns true if the device is a tablet (600 <= width < 1100).
  bool get isTablet => width >= 600 && width < 1100;

  /// Returns true if the device is desktop (width >= 1100).
  bool get isDesktop => width >= 1100;

  /// Returns a width percentage (e.g., 50% of the screen width).
  double wp(double percentage) => width * percentage / 100;

  /// Returns a height percentage (e.g., 50% of the screen height).
  double hp(double percentage) => height * percentage / 100;
}

 

Localization with easy_localization ๐ŸŒ

1. Translation Files: Create the folder assets/translations/ and add your JSON translation files.

assets/translations/en.json:

{
  "title": "Clean Architecture Flutter App",
  "home_screen": "Home Screen",
  "welcome_message": "Welcome to our app!"
}

assets/translations/es.json:

{
  "title": "Aplicaciรณn Flutter de Arquitectura Limpia",
  "home_screen": "Pantalla Principal",
  "welcome_message": "ยกBienvenido a nuestra aplicaciรณn!"
}

No additional code is needed for easy_localizationโ€”the configuration is done in main.dart (see below).
 

4. Main Application Setup (main.dart) ๐ŸŽฏ

Create or update lib/main.dart:

import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'core/theme/app_theme.dart';
import 'features/feature_name/presentation/screens/home_screen.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();

  runApp(
    EasyLocalization(
      supportedLocales: const [Locale('en'), Locale('es')],
      path: 'assets/translations', // Path to your translations folder
      fallbackLocale: const Locale('en'),
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: tr('title'),
      debugShowCheckedModeBanner: false,
      theme: AppTheme.lightTheme(),
      darkTheme: AppTheme.darkTheme(),
      // Dynamically switch themes based on system settings
      themeMode: ThemeMode.system,
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      home: const HomeScreen(),
    );
  }
}

 

5. Sample Home Screen (home_screen.dart) ๐Ÿ“ฑ

Create lib/features/feature_name/presentation/screens/home_screen.dart:

import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import '../../../core/responsive/responsive.dart';

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

  @override
  Widget build(BuildContext context) {
    final responsive = Responsive(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(tr('home_screen')),
      ),
      body: Center(
        child: Padding(
          padding: EdgeInsets.all(responsive.wp(5)), // 5% of screen width as padding
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                tr('welcome_message'),
                style: TextStyle(fontSize: responsive.wp(5)), // Responsive font size
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 20),
              Text(
                'Screen width: ${responsive.width.toStringAsFixed(2)}',
                style: TextStyle(fontSize: responsive.wp(4)),
              ),
              Text(
                'Screen height: ${responsive.height.toStringAsFixed(2)}',
                style: TextStyle(fontSize: responsive.wp(4)),
              ),
              Text(
                'Is Mobile: ${responsive.isMobile}',
                style: TextStyle(fontSize: responsive.wp(4)),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

 

6. Module Scaffolding Shell Script โš™๏ธ

To automate the creation of base folders and starter files (including our theme and responsive files), create a shell script named setup_project.sh in the project root:

#!/bin/bash

# ------------------------------
# SETUP PROJECT STRUCTURE SCRIPT
# ------------------------------
#
# This script creates the base folder structure in the "lib" directory,
# including core folders and files for theme and responsive utilities.
#
# Optionally, if you pass a module name as an argument, it will also scaffold
# the folder structure for that feature/module.
#
# Usage:
#   ./setup_project.sh [ModuleName]
#
# Example:
#   ./setup_project.sh user_profile
#
# ------------------------------

# Create base core directories
echo "๐Ÿ“ Creating core folders..."
mkdir -p lib/core/theme
mkdir -p lib/core/responsive

# Create features folder if it doesn't exist
mkdir -p lib/features

# Create basic theme file with starter content
echo "๐Ÿ“ Creating lib/core/theme/app_theme.dart..."
cat << 'EOF' > lib/core/theme/app_theme.dart
import 'package:flutter/material.dart';

class AppTheme {
  /// Returns the light theme configuration.
  static ThemeData lightTheme() {
    return ThemeData(
      primarySwatch: Colors.blue,
      brightness: Brightness.light,
      visualDensity: VisualDensity.adaptivePlatformDensity,
      // Add other light theme configurations (fonts, icon themes, etc.)
    );
  }

  /// Returns the dark theme configuration.
  static ThemeData darkTheme() {
    return ThemeData(
      primarySwatch: Colors.blue,
      brightness: Brightness.dark,
      visualDensity: VisualDensity.adaptivePlatformDensity,
      // Add other dark theme configurations
    );
  }
}
EOF

# Create basic responsive file with starter content
echo "๐Ÿ“ Creating lib/core/responsive/responsive.dart..."
cat << 'EOF' > lib/core/responsive/responsive.dart
import 'package:flutter/material.dart';

class Responsive {
  final BuildContext context;
  Responsive(this.context);

  /// Returns the screen width.
  double get width => MediaQuery.of(context).size.width;

  /// Returns the screen height.
  double get height => MediaQuery.of(context).size.height;

  /// Determines if the device is mobile.
  bool get isMobile => width < 600;

  /// Determines if the device is a tablet.
  bool get isTablet => width >= 600 && width < 1100;

  /// Determines if the device is a desktop.
  bool get isDesktop => width >= 1100;

  /// Returns width as a percentage of the total screen width.
  double wp(double percentage) => width * percentage / 100;

  /// Returns height as a percentage of the total screen height.
  double hp(double percentage) => height * percentage / 100;
}
EOF

# Optional: If a module name is provided, scaffold the module structure.
if [ -n "$1" ]; then
  MODULE_NAME=$1
  echo "๐Ÿ“ Creating module structure for: $MODULE_NAME ..."
  
  # Create the feature base directory
  mkdir -p lib/features/$MODULE_NAME

  # Create Data Layer folders
  mkdir -p lib/features/$MODULE_NAME/data/datasources
  mkdir -p lib/features/$MODULE_NAME/data/models
  mkdir -p lib/features/$MODULE_NAME/data/repositories

  # Create Domain Layer folders
  mkdir -p lib/features/$MODULE_NAME/domain/entities
  mkdir -p lib/features/$MODULE_NAME/domain/repositories
  mkdir -p lib/features/$MODULE_NAME/domain/usecases

  # Create Presentation Layer folders
  mkdir -p lib/features/$MODULE_NAME/presentation/screens
  mkdir -p lib/features/$MODULE_NAME/presentation/widgets
  mkdir -p lib/features/$MODULE_NAME/presentation/bloc
  mkdir -p lib/features/$MODULE_NAME/presentation/provider

  echo "โœ… Module '$MODULE_NAME' structure created successfully."
fi

echo "๐ŸŽ‰ Project structure created with basic theme and responsive files."

 

7. Git Hooks & Linter Configuration ๐Ÿ”’

To enforce code quality, add a strict analysis_options.yaml and set up a Git pre-commit hook.

analysis_options.yaml

# analysis_options.yaml

include: package:flutter_lints/flutter.yaml

analyzer:
  strong-mode: true
  errors:
    missing_return: error
    avoid_print: error

linter:
  rules:
    always_declare_return_types: true
    always_specify_types: true
    avoid_empty_else: true
    avoid_init_to_null: true
    avoid_null_checks_in_equality_operators: true
    prefer_const_constructors: true
    prefer_const_literals_to_create_immutables: true
    use_key_in_widget_constructors: true

 

Git Pre-commit Hook

Create a file named pre-commit in the .git/hooks/ directory with the following content:

#!/bin/sh
# .git/hooks/pre-commit

echo "๐Ÿ” Running flutter analyze..."
flutter analyze

RESULT=$?
if [ $RESULT -ne 0 ]; then
  echo "๐Ÿšซ Linting issues found. Please resolve them before committing."
  exit 1
fi

exit 0

Then make it executable:

chmod +x .git/hooks/pre-commit

 

8. Final Thoughts ๐ŸŒŸ

Architecture & Structure: Our Clean Architecture setup separates concerns into core, features, domain, and data layersโ€”making the project scalable and maintainable.

Core Utilities: With pre-built theming, responsiveness, and localization (using easy_localization), our app will have consistent styling and support multiple languages out of the box.

Automation & Quality: The provided shell script accelerates module creation, and our linter & Git hook setup enforce strict code quality.

State Management: Both BLoC and Provider have been integrated (in main.dart) so you can choose the best solution per feature.

Letโ€™s work together to build a robust, scalable, and maintainable Flutter application! Happy coding! ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

This document should serve as the single source of truth for setting up new Flutter projects within our team. If you have any questions or suggestions, please reach out!