Base Project
Creating a Base Project in Flutter
This article is complete when combined with Clean Architecture and Package.
Why Do You Need a Base Project?
Any Flutter developer, after working on multiple projects, wants to create a project template to speed up the initialization of future projects. However, extracting reusable parts and setting up the project structure from scratch can be time-consuming and tedious.
To solve this, I explored various ways to automate the creation of essential files and folders. One approach is using Windows command-line tools to generate files, but a more powerful tool that can save time for you and your team is Mason.
If you're unfamiliar with Mason, check out my guide: Boost Your Flutter Development Efficiency with Mason
Essential Libraries for a Base Project
Below is a list of important libraries that I use to ensure the code is clean, scalable, and maintainable.
Dependency Injection with get_it
get_it
Helps with data retrieval and dependency injection.
Allows access to repositories anywhere in the project without manually passing data between classes.
Routing Management with go_router
go_router
Official Flutter routing library—works well for both mobile and web.
Provides a clear and scalable way to manage navigation.
State Management with flutter_bloc
flutter_bloc
One of the most popular and efficient state management libraries.
If you're new to
bloc
, check out my guide:
Code Generation with json_serializable
& freezed
json_serializable
& freezed
json_serializable on pub.dev freezed on pub.dev
Reduces repetitive boilerplate code.
Automatically generates helpful functions like
copyWith
,fromJson
, andtoJson
for easier data handling.
Code Quality Improvement with lint
lint
Enforces Effective Dart coding standards.
Ensures consistent and readable code across teams.
If you haven’t read Effective Dart, check it out here: Effective Dart.
App Icon Setup with flutter_launcher_icons
flutter_launcher_icons
flutter_launcher_icons on pub.dev
Automatically generates app icons for both Android and iOS.
Saves time when setting up project branding.
Creating a Base Project with Mason
Below is how I structure the lib/
directory in my base project:
lib/
│── main.dart # Runs the app, supports dev, staging, production environments
│── router/ # Manages routes using `go_router`
│── helper/ # Contains utility functions (e.g., localization, utilities)
│── features/ # Stores the app’s main features, clearly separated
│── config/ # Holds environment settings, API configurations, etc.
Outside of the lib/
folder, I also set up:
assets/ # Stores images and localization files
HELP.md # Project setup guide
CHANGELOG.md # Records version changes
analysis_options.yaml # Linting rules
pubspec.yaml # Dependency management
build.yaml # Build configuration
You can check out my base project template, which is built using Mason, here: dr_base_project on BrickHub
Setting Up the Development Environment
A well-configured development environment helps prevent issues before the app reaches users.
To easily switch between environments (dev, staging, production) without manual changes, I use an enum
to store environment settings.
Defining the Environment Enum
late EnviEnum ourEnvi;
enum EnviEnum {
develop(
code: 0,
title: "develop",
config: _BaseUrlConfig(baseUrl: "http://192.168.20.82:5173/"),
),
staging(
code: 1,
title: "staging",
config: _BaseUrlConfig(baseUrl: "https://staging-partner.kdmp.net/"),
),
product(
code: 2,
title: "product",
config: _BaseUrlConfig(baseUrl: "https://partners.kdmp.net/"),
);
const EnviEnum({required this.code, required this.title, required this.config});
final int code;
final String title;
final _BaseUrlConfig config;
String get baseUrl => config.baseUrl;
}
class _BaseUrlConfig {
final String baseUrl;
const _BaseUrlConfig({required this.baseUrl});
}
You can extend this enum to include additional configurations like API keys, logging settings, and more.
Initializing the App for Each Environment
Development Environment (Local Server)
void main() {
ourEnvi = EnviEnum.develop;
myMain(() {
setup();
runApp(const App());
});
}
Staging Environment (Internal Testing Before Release)
void main() {
ourEnvi = EnviEnum.staging;
myMain(() {
setup();
runApp(const App());
});
}
Production Environment (Final Release for Users)
void main() {
ourEnvi = EnviEnum.product;
myMain(() {
setup();
runApp(const App());
});
}
Conclusion
Setting up a base project in Flutter saves a lot of time when starting a new project, making it easier to maintain and scale.
Use Mason to automatically generate necessary files and directories.
Leverage popular libraries such as
go_router
,flutter_bloc
,json_serializable
, andfreezed
to enhance development efficiency.Configure dev, staging, and production environments to better manage application environments.
Last updated