
Creating a reusable Flutter package and sharing it on pub.dev transforms you from a consumer of the ecosystem into a contributor. Flutter package publishing isn’t just about sharing code—it’s about building something others can depend on, learning best practices for API design, and establishing credibility in the Flutter community.
This guide walks through the complete Flutter package publishing process, from initial setup through your first release and beyond. You’ll learn how to structure your package for discoverability, write documentation that helps users succeed, and maintain your package over time. Whether you’re publishing a utility library, UI component, or platform integration, these practices will help your package stand out.
Why Publish Your Flutter Package
Publishing to pub.dev offers benefits beyond code sharing:
Community contribution. The package you build might solve a problem hundreds of developers face. Your solution saves them hours of development time.
Code quality improvement. Knowing others will use your code motivates better architecture, documentation, and testing. The publishing requirements themselves enforce good practices.
Professional credibility. A well-maintained package on pub.dev demonstrates real-world Flutter expertise more effectively than any resume bullet point.
Learning opportunity. The process teaches versioning, API design, documentation, and maintenance—skills that improve all your code, not just packages.
Creating Your Flutter Package
Start with the package template to get the correct project structure:
flutter create --template=package my_package_name
This creates a directory with the essential files:
my_package_name/
├── lib/
│ └── my_package_name.dart # Main library file
├── test/
│ └── my_package_name_test.dart
├── CHANGELOG.md
├── LICENSE
├── README.md
├── pubspec.yaml
└── analysis_options.yaml
Choosing a Package Name
Package names on pub.dev are permanent and globally unique. Choose carefully:
- Use lowercase letters and underscores only
- Make it descriptive but concise
- Avoid generic names like “utils” or “helpers”
- Check pub.dev first to ensure availability
- Consider searchability—will users find it?
Good names: flutter_animate, cached_network_image, riverpod
Avoid: my_utils, cool_package, flutter_stuff
Configuring pubspec.yaml
The pubspec.yaml file defines your package’s metadata. Every field affects discoverability and user trust:
name: responsive_grid_layout
description: A flexible grid layout widget that adapts to screen sizes with customizable breakpoints and gap handling.
version: 1.0.0
homepage: https://github.com/yourusername/responsive_grid_layout
repository: https://github.com/yourusername/responsive_grid_layout
issue_tracker: https://github.com/yourusername/responsive_grid_layout/issues
documentation: https://yourusername.github.io/responsive_grid_layout/
topics:
- ui
- layout
- responsive
- grid
- widgets
environment:
sdk: '>=3.0.0 <4.0.0'
flutter: '>=3.10.0'
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
Understanding Key Fields
description: Limited to 180 characters. Make it specific and keyword-rich. This appears in search results and affects ranking.
version: Follow semantic versioning. Start at 0.0.1 for pre-release or 1.0.0 if your API is stable.
homepage/repository: Required for credibility. GitHub repositories let users inspect code, file issues, and contribute.
topics: Up to 5 topics help categorization. Use common terms users might search for.
environment: Specify minimum SDK versions. Be as permissive as your code allows to maximize compatibility.
Writing Package Code
Package code requires more discipline than application code because others depend on your API stability.
API Design Principles
Export only what users need. The main library file controls your public API:
// lib/responsive_grid_layout.dart
library responsive_grid_layout;
// Public API
export 'src/responsive_grid.dart';
export 'src/breakpoints.dart';
export 'src/grid_item.dart';
// Don't export internal implementation details
// src/internal_helpers.dart stays private
Use clear, consistent naming. Follow Dart conventions. Prefix private members with underscore. Use descriptive names over abbreviations.
Document public APIs. Every public class, method, and property needs doc comments:
/// A responsive grid layout that adapts to available width.
///
/// The grid automatically adjusts column count based on [breakpoints].
/// Items flow left-to-right, top-to-bottom.
///
/// Example:
/// ```dart
/// ResponsiveGrid(
/// breakpoints: Breakpoints(sm: 600, md: 900, lg: 1200),
/// children: [
/// GridItem(child: Card(...)),
/// GridItem(span: 2, child: Card(...)),
/// ],
/// )
/// ```
///
/// See also:
/// * [GridItem], for configuring individual grid items
/// * [Breakpoints], for customizing responsive behavior
class ResponsiveGrid extends StatelessWidget {
/// Creates a responsive grid layout.
///
/// The [children] parameter must not be null.
/// If [breakpoints] is null, defaults are used.
const ResponsiveGrid({
super.key,
required this.children,
this.breakpoints,
this.gap = 16.0,
});
/// The widgets to display in the grid.
final List children;
/// Defines column counts at different screen widths.
///
/// If null, uses default breakpoints: sm=1, md=2, lg=3, xl=4.
final Breakpoints? breakpoints;
/// The spacing between grid items in logical pixels.
///
/// Defaults to 16.0.
final double gap;
@override
Widget build(BuildContext context) {
// Implementation
}
}
Declaring Platform Support
If your package works on specific platforms only, declare it:
flutter:
plugin:
platforms:
android:
package: com.example.my_plugin
pluginClass: MyPlugin
ios:
pluginClass: MyPlugin
For pure Dart packages that work everywhere, no platform declaration is needed.
Testing Your Package
Pub.dev displays test coverage and running tests builds user trust. Aim for comprehensive coverage:
import 'package:flutter_test/flutter_test.dart';
import 'package:responsive_grid_layout/responsive_grid_layout.dart';
void main() {
group('ResponsiveGrid', () {
testWidgets('renders children correctly', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: ResponsiveGrid(
children: [
GridItem(child: Text('Item 1')),
GridItem(child: Text('Item 2')),
],
),
),
);
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 2'), findsOneWidget);
});
testWidgets('applies custom gap spacing', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: ResponsiveGrid(
gap: 24.0,
children: [
GridItem(child: Container()),
GridItem(child: Container()),
],
),
),
);
// Verify gap is applied
// ...
});
testWidgets('adapts columns at breakpoints', (tester) async {
tester.binding.window.physicalSizeTestValue = Size(800, 600);
tester.binding.window.devicePixelRatioTestValue = 1.0;
await tester.pumpWidget(
MaterialApp(
home: ResponsiveGrid(
breakpoints: Breakpoints(sm: 600, md: 900),
children: List.generate(6, (_) => GridItem(child: Container())),
),
),
);
// At 800px width (between sm and md), should show 2 columns
// Verify layout
// ...
});
});
group('Breakpoints', () {
test('returns correct column count for width', () {
final breakpoints = Breakpoints(sm: 600, md: 900, lg: 1200);
expect(breakpoints.columnsFor(500), 1); // Below sm
expect(breakpoints.columnsFor(700), 2); // Between sm and md
expect(breakpoints.columnsFor(1000), 3); // Between md and lg
expect(breakpoints.columnsFor(1400), 4); // Above lg
});
});
}
Run tests with:
flutter test
Writing Documentation
Documentation determines whether users adopt your package. Invest time here.
Creating an Effective README
Your README should answer these questions in order:
- What does this package do? One paragraph summary.
- How do I install it? Copy-paste installation instructions.
- How do I use it? Simple example that works immediately.
- What options are available? API overview with examples.
- Where can I get help? Links to issues, discussions, docs.
# Responsive Grid Layout
A flexible grid layout widget that adapts to screen sizes with customizable breakpoints.
[](https://pub.dev/packages/responsive_grid_layout)
[](https://pub.dev/packages/responsive_grid_layout/score)
## Features
- Automatic column adjustment based on screen width
- Customizable breakpoints
- Flexible item spanning
- Configurable gap spacing
## Installation
```yaml
dependencies:
responsive_grid_layout: ^1.0.0
```
## Quick Start
```dart
import 'package:responsive_grid_layout/responsive_grid_layout.dart';
ResponsiveGrid(
children: [
GridItem(child: Card(child: Text('Item 1'))),
GridItem(child: Card(child: Text('Item 2'))),
GridItem(span: 2, child: Card(child: Text('Wide Item'))),
],
)
```
## Customization
### Custom Breakpoints
```dart
ResponsiveGrid(
breakpoints: Breakpoints(
sm: 600, // 1 column below this
md: 900, // 2 columns
lg: 1200, // 3 columns
xl: 1600, // 4 columns
),
children: [...],
)
```
## Contributing
Contributions are welcome! Please read our [contributing guide](CONTRIBUTING.md).
Maintaining CHANGELOG
Document every release with user-focused descriptions:
## [1.1.0] - 2025-04-15
### Added
- `crossAxisAlignment` parameter for item alignment
- Support for RTL layouts
### Fixed
- Gap calculation when items span multiple columns
## [1.0.0] - 2025-04-01
### Added
- Initial release
- ResponsiveGrid widget with breakpoint support
- GridItem with span configuration
- Customizable gap spacing
Publishing to pub.dev
Before publishing, verify everything is correct with a dry run:
dart pub publish --dry-run
This validates your package without uploading. Fix any warnings or errors it reports.
Common issues include:
- Missing LICENSE file
- Description too long (max 180 characters)
- Missing homepage or repository URL
- SDK constraints too restrictive
When ready, publish:
dart pub publish
You’ll authenticate with your Google account and confirm the upload. Once published, your package appears on pub.dev within minutes.
After Publishing: Maintenance
Publishing is just the beginning. Maintained packages earn more trust and usage.
Responding to Issues
Monitor your GitHub issues. Prompt responses—even just acknowledging the issue—build community trust. Label issues appropriately (bug, enhancement, question) to organize your backlog.
Version Updates
Follow semantic versioning strictly:
- Patch (1.0.x): Bug fixes, no API changes
- Minor (1.x.0): New features, backward compatible
- Major (x.0.0): Breaking changes
To publish an update:
- Update version in
pubspec.yaml - Add entry to
CHANGELOG.md - Run
dart pub publish
Handling Deprecation
When changing APIs, deprecate before removing:
@Deprecated('Use ResponsiveGrid instead. Will be removed in v2.0.0')
class FlexibleGrid extends ResponsiveGrid {
// Forward to new implementation
}
Maximizing Your pub.dev Score
Pub.dev scores packages on several factors. Higher scores mean better visibility:
- Follow Dart conventions: Use
flutter_lintsor stricter analysis - Document all public APIs: Doc comments on every public member
- Provide examples: Include an
example/directory with runnable code - Support multiple platforms: When possible, work on all Flutter platforms
- Pass static analysis: Zero warnings from
dart analyze
Contributing to the Flutter Ecosystem
Flutter package publishing transforms your useful code into community resources. Start with something small—a widget you’ve built multiple times, a utility function you copy between projects, or a wrapper around a complex API. The process of packaging it properly will improve your skills, and others will benefit from your work.
Focus on quality over quantity. One well-maintained, well-documented package builds more credibility than ten abandoned experiments. Respond to issues, update dependencies, and iterate based on feedback. That’s how packages become Flutter Favorites.
For related Flutter development practices, explore our guides on Clean Architecture with Dependency Injection and Flutter Testing Best Practices—both essential for building packages others can rely on.