Dart Cursor Rules: Cross-Platform Development Guide
Cursor rules for Dart development covering null safety, async programming, streams, isolates, and package management for Flutter and server-side applications.
Overview
Dart is a versatile, client-optimized language essential for building natively compiled applications for mobile, web, and desktop, primarily powering the Flutter framework. These cursor rules enforce strict null safety, robust asynchronous programming, and efficient isolate usage to help AI assistants generate type-safe, high-performance code. Whether you're developing a cross-platform UI or a backend server application, these rules ensure your Dart code is clean, efficient, and perfectly aligned with the Flutter ecosystem.
Note:
Enforces null safety conventions, async/await patterns, stream handling, and immutable data practices.
Rules Configuration
---
description: Enforces best practices for Dart development, focusing on null safety, async programming, and Flutter integration. Provides comprehensive guidelines for writing clean, performant cross-platform code with proper context.
globs: **/*.dart
---
# Dart Best Practices
You are an expert in Dart development and related cross-platform technologies.
You understand modern Dart development practices, architectural patterns, and the importance of providing complete context in code generation.
### Context-Aware Code Generation
- Provide complete module context including imports, exports, and library declarations
- Include pubspec.yaml and analysis_options.yaml when generating project code
- Generate full function signatures with proper types and DartDoc documentation
- Include DartDoc comments explaining purpose, parameters, and return values
- Provide context about the module's role in the larger system architecture
### Null Safety & Type System
- Always use sound null safety with proper nullable (? ) and non-nullable types
- Use late for lazy initialization of non-nullable fields that are set after construction
- Prefer final/const for immutability wherever possible
- Use const constructors for compile-time constant widgets and data objects
- Leverage Dart 3+ features: records for compound returns, patterns for destructuring, sealed classes for restricted type hierarchies
### Async & Stream Patterns
- Use async/await for all asynchronous operations over raw .then() chaining
- Prefer Future for single async values, Stream for sequences of async data
- Handle stream errors with .handleError() or try/catch in async for loops
- Cancel stream subscriptions using StreamSubscription.cancel() to prevent leaks
- Use StreamController with proper close() and drain() for custom streams
### Best Practices
- Use extension methods to add functionality to existing types without inheritance
- Prefer collection-if and spread operators (..., ...?) for clean list/map building
- Use factory constructors for complex object creation logic
- Implement copyWith methods for immutable data classes
- Use sealed classes for restricted type hierarchies and exhaustive pattern matching
### State Management
- Use Provider or Riverpod for dependency injection and reactive state
- Keep business logic in ChangeNotifier or StateNotifier classes, not in widgets
- Use Consumer and Selector for granular widget rebuilds
- Leverage ValueNotifier and ValueListenableBuilder for simple scalar state
- Use StatefulWidget only when Provider-based state is overkill
### Testing & Quality
- Write unit tests with proper Arrange-Act-Assert structure and descriptive names
- Use mockito or mocktail for dependency mocking in widget tests
- Test async code with expectLater, completes, and throwsA matchers
- Run dart analyze before commits to catch static issues early
- Enforce team conventions with custom lint rules in analysis_options.yaml
### Performance
- Use const constructors aggressively to reduce widget rebuilds and object allocation
- Use compute() or Isolate.run() for CPU-bound work off the main thread
- Cache expensive computations using memoization patterns
- Prefer indexed access over .firstWhere() for performance-critical loops
Installation
Create dart.mdc in your project's .cursor/rules/ directory and paste the configuration above. Cursor and Windsurf both read .cursor/rules/ — Copilot users place it in .github/copilot-instructions.md instead.
Examples
// user_service.dart — Null-safe model with copyWith and sealed class
sealed class UserState {}
class UserLoading extends UserState {}
class UserLoaded extends UserState {
final User user;
UserLoaded(this.user);
}
class User with _$User {
final String id;
final String email;
const User({required this.id, required this.email});
User copyWith({String? id, String? email}) => User(
id: id ?? this.id,
email: email ?? this.email,
);
}
// providers/counter_provider.dart — Riverpod state management
import 'package:riverpod/riverpod.dart';
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
void reset() => state = 0;
}
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
// Usage in widget:
// final count = ref.watch(counterProvider);
// ref.read(counterProvider.notifier).increment();
Related Resources
Related Articles
Astro Cursor Rules: Islands Architecture & Static Content
Comprehensive Astro cursor rules covering component islands, static generation, content collections, and hydration directives for fast, SEO-friendly sites.
AI Rules in Modern IDEs: Global and Project-Specific Configurations
AI rules customize AI assistants in modern IDEs like Cursor, Windsurf, and VSCode Copilot. Learn to configure global and project-specific rules for consistent, high-quality code.
AI Rule Best Practices: Configure, Manage, and Optimize
Master AI rule configuration for development. Learn best practices to implement, manage, and optimize AI rules, ensuring code quality, consistency, and enhanced developer workflows.