flutter — Cursor rule: Flutter project standards
A Cursor rule that pins down Flutter code style: formatting, lints, MVVM layers and Riverpod. Useful when the agent mixes widgets and state in one file.
.cursor/rules/flutter.mdcWhat flutter does
Drop .cursor/rules/flutter.mdc into your repo and Cursor reads it on every request. The rule covers formatting through dart format, editor.formatOnSave in the IDE, and static analysis with flutter_lints. Style arguments stop, and common mistakes get caught earlier.
Project layout follows MVVM. The UI layer holds Views and ViewModels; the data layer holds Repositories and Services. Files are grouped by feature: features/auth/presentation/screens, features/auth/domain/models, features/auth/data/services. Riverpod handles state and dependency injection, with a Provider for the repository and a StateNotifierProvider for the view model in the examples.
The examples assume Dart 3.10+ and modern syntax such as const constructors and super.key. On an older SDK, or in a codebase built on Provider and setState, you will rewrite them to fit — check your SDK version before pasting the rule in.
What it helps with
- settle on one formatting and lint setup across the team
- split a Flutter app into features and layers
- move state out of widgets into view models
- wire up Riverpod instead of manual dependency injection
- show the agent examples of good and bad Flutter code
Example prompts for the agent
- Build a login screen following the rule:
features/auth/presentation/screens/login_screen.dartplus its view model. - Refactor this widget into MVVM with Riverpod as the flutter rule describes.
- Check my
main.dartagainst the rule: const constructors, formatting, lints.
How to install flutter
Manually: put the files in place
.cursor/rules/flutter.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/flutter.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/flutter.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/flutter.mdManually: put the files in place
.clinerules/flutter.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about flutter
How do I install the flutter rule in Cursor?
Create .cursor/rules/flutter.mdc in your project root and paste the rule contents into it. Cursor picks it up automatically.
What does the flutter rule do?
It gives the agent Flutter standards: formatting and lints, feature-based structure, a UI and Data layer split, and Riverpod for state and dependencies.
Which Dart version does the rule target?
The examples use Dart 3.10+ syntax like const constructors and super.key. On an older SDK you will need to adapt them.
Source text
flutter.mdc · CC0-1.0
---
description: Definitive guidelines for writing high-quality, performant, and maintainable Flutter applications using modern Dart 3.10+ practices.
globs: **/*
---
# flutter Best Practices
## Code Organization and Structure
### 1.1 Enforce Consistent Formatting and Linting
Always use `dart format` and enable `editor.formatOnSave` in your IDE. Integrate `flutter_lints` for robust static analysis. This eliminates style debates and catches common errors early.
❌ BAD (Manual formatting, inconsistent style)
```dart
// main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(title: 'My App', home: MyHomePage());
}
}
```
✅ GOOD (Automated formatting, `flutter_lints` enabled)
```dart
// main.dart
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: const MyHomePage(),
);
}
}
```
### 1.2 Adopt MVVM with Clear Layer Separation
Separate your application into distinct UI and Data layers. The UI layer consists of `Views` (widgets) and `ViewModels` (state logic). The Data layer comprises `Repositories` (business logic, data access) and `Services` (external API calls). This ensures maintainability and testability.
* **`lib/` structure:**
* `features/`: Group by feature (e.g., `auth/`, `products/`).
* `auth/`:
* `presentation/`:
* `screens/`: `login_screen.dart` (View)
* `viewmodels/`: `login_viewmodel.dart` (ViewModel)
* `domain/`:
* `models/`: `user.dart` (Immutable data model)
* `repositories/`: `auth_repository.dart` (Abstract interface)
* `data/`:
* `repositories/`: `auth_repository_impl.dart` (Concrete implementation)
* `services/`: `auth_api_service.dart` (API calls)
### 1.3 Use Riverpod for State Management and Dependency Injection
Riverpod is the definitive choice for state management and dependency injection. It provides compile-time safety, simplifies testing, and eliminates common `Provider` pitfalls.
❌ BAD (InheritedWidget/Provider for DI, manual state updates)
```dart
// In a widget
final userRepo = Provider.of<UserRepository>(context);
// ...
userRepo.fetchUsers().then((_) => setState(() { /* ... */ }));
```
✅ GOOD (Riverpod for DI and state, auto-rebuilds)
```dart
// providers.dart
final authRepositoryProvider = Provider<AuthRepository>((ref) => AuthRepositoryImpl(ref.read(authApiService)));
final loginViewModelProvider = StateNotifierProvider<LoginViewModel, LoginState>((ref) => LoginViewModel(ref.read(authRepositoryProvider)));
// login_screen.dart (View)
class LoginScreen extends ConsumerWidget {
const LoginScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final loginState = ref.watch(loginViewModelProvider);
// ... UI with loginState.isLoading, loginState.error, etc.
ElevatedButton(
onPressed
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc