← Articles

Publishing a Flutter package to pub.dev

By Charlin Joe · 9 June 2025

Publishing a Flutter package to pub.dev is straightforward once you understand what the automated scoring system checks and what makes a package trustworthy for other developers. A 130/140 pub points score and a well-structured package will get noticed; a rushed publish with a bare README will sit at the bottom of search results.

Package structure

my_package/
├── lib/
│   ├── my_package.dart        # Public API barrel file
│   └── src/                   # Implementation (not exported directly)
│       ├── feature_a.dart
│       └── feature_b.dart
├── test/
│   └── my_package_test.dart
├── example/
│   └── lib/
│       └── main.dart          # Working Flutter example app
├── CHANGELOG.md
├── LICENSE
├── README.md
└── pubspec.yaml

The src/ directory is convention — it signals that these files are internal implementation details, not part of the public API.

pubspec.yaml

name: my_flutter_package
description: >
  A clear, one-sentence description of what the package does.
  Avoid words like "simple", "easy", or "best".
version: 0.1.0
homepage: https://github.com/yourorg/my_flutter_package
repository: https://github.com/yourorg/my_flutter_package
issue_tracker: https://github.com/yourorg/my_flutter_package/issues

environment:
  sdk: '>=3.0.0 <4.0.0'
  flutter: '>=3.10.0'

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^4.0.0

Key points:

  • Version follows semantic versioning: MAJOR.MINOR.PATCH
  • Include repository and issue_tracker — these earn pub points
  • Prefer a narrow SDK lower bound (>=3.0.0) and open upper bound (<4.0.0)

The barrel file

Export your public API explicitly:

// lib/my_flutter_package.dart
export 'src/feature_a.dart' show PublicClassA, PublicEnum;
export 'src/feature_b.dart';
// Don't export internal helpers

Using show lets you expose only what's intentional and hide internal classes even within the same file.

dart doc comments

Pub.dev's scoring checks for documentation coverage. Document all public APIs:

/// A widget that animates its child into view from below.
///
/// The [duration] controls how long the animation takes. Defaults to 300ms.
/// The [curve] controls the easing. Defaults to [Curves.easeOut].
///
/// Example:
/// ```dart
/// SlideInWidget(
///   child: const Text('Hello'),
/// )
/// ```
class SlideInWidget extends StatefulWidget {
  /// Creates a [SlideInWidget].
  const SlideInWidget({
    super.key,
    required this.child,
    this.duration = const Duration(milliseconds: 300),
    this.curve = Curves.easeOut,
  });

  /// The widget to animate.
  final Widget child;

  /// How long the slide animation takes.
  final Duration duration;

  /// The animation curve.
  final Curve curve;

Writing a good README

The README is your package's landing page on pub.dev. Include:

  1. What it does — one paragraph, no fluff
  2. Installation — copy-paste pubspec.yaml snippet
  3. Quick start — working code example, 10-30 lines
  4. API overview — key classes and their purpose
  5. Platform support table (for multi-platform packages)
  6. License

CHANGELOG.md format

Pub.dev parses your CHANGELOG. Use this format:

## 0.2.0

- Added `SlideInWidget` for animating children into view
- **Breaking:** Renamed `MyWidget.color` to `MyWidget.backgroundColor`

## 0.1.1

- Fixed null safety issue in `FeatureA`

## 0.1.0

- Initial release

Pre-publish checks

# Analyze code
flutter analyze

# Run tests
flutter test

# Check what will be published
dar pub publish --dry-run

# Check pub points locally
dart pub publish --dry-run 2>&1 | grep -A5 'Grant'

Dry run shows exactly what files will be included and flags issues with formatting, license, and documentation.

Publishing

dart pub publish

This opens a browser for authentication, then uploads. The package is publicly available immediately.

Automated publishing with GitHub Actions

name: Publish
on:
  push:
    tags: ['v*']

jobs:
  publish:
    permissions:
      id-token: write  # Required for OIDC auth with pub.dev
      contents: read
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1

This uses pub.dev's OIDC-based automated publishing — no stored token needed. Configure it in pub.dev under package settings → Automated publishing.

Semantic versioning guide

ChangeVersion bump
Bug fix, no API changePatch: 0.1.00.1.1
New feature, backwards compatibleMinor: 0.1.00.2.0
Breaking changeMajor: 0.1.01.0.0 (or 0.1.00.2.0 while pre-1.0)

Pre-1.0, breaking changes are allowed in minor versions. Once you publish 1.0.0, breaking changes require a major bump.

Common pitfalls

Publishing before testing on a fresh project. Create a new Flutter project and add your package as a path dependency. If it doesn't work out of the box, it won't for your users either.

Not specifying platform support. If your package uses platform channels, declare it:

flutter:
  plugin:
    platforms:
      android:
        package: com.example.my_package
        pluginClass: MyPackagePlugin
      ios:
        pluginClass: MyPackagePlugin

Uploading with sensitive files. Files in .pubignore are excluded (similar to .gitignore). Make sure .env, config files with keys, and test fixtures with real data are excluded.

Yanking instead of deprecating. Yanking a version breaks existing users who have it pinned. Only yank if the version has a critical security issue. For everything else, publish a new version and mark the old one as discontinued.

Sign in to like, dislike, or report.

Publishing a Flutter package to pub.dev — ANN Tech