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
- Project Overview & Folder Structure 🗂
- Dependencies & pubspec.yaml Setup 📦
- Core Modules Setup 🛠
- Main Application Setup (main.dart) 🎯
- Sample Home Screen (home_screen.dart) 📱
- Module Scaffolding Shell Script ⚙️
- Git Hooks & Linter Configuration 🔒
- 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!
NCompas AI