Back to all articles
Flutter & Dart11 min readMarch 5, 2026

Publishing Your First Package on Pub.dev: Lessons from Authoring flutter_devlog

Everything you need to know about building, testing, documenting, and publishing open-source Dart & Flutter packages with high pana scores.

Bayajit Islam

Written by Bayajit Islam

Freelance Flutter & Backend Developer • Dhaka, Bangladesh

Publishing Your First Package on Pub.dev: Lessons from Authoring flutter_devlog
Publishing an open-source package to Pub.dev is one of the most rewarding milestones in a Dart developer's career. But creating a package that earns the coveted 140/140 Pana score, gains developer trust, and remains maintainable across multiple Flutter SDK releases requires meticulous attention to detail. When I engineered and published flutter_devlog — a lightweight, structured logging utility — I documented the entire playbook. Here is your definitive guide to package authorship on Pub.dev, from directory structuring to automated CI/CD publishing via GitHub Actions.

Scaffolding: Package vs Plugin Anatomy

Before writing code, understand the architectural distinction between a pure Dart Package and a Flutter Plugin. A pure Dart package contains only Dart code that runs on any platform (e.g., utility functions, mathematical algorithms, data serialization, business models). A Flutter plugin contains platform-specific native code (Kotlin/Java for Android, Swift/Objective-C for iOS, C++ for desktop) communicating across platform channels or FFI.

Keep your dependencies as lean as possible. A library that pulls in 15 third-party dependencies becomes a dependency conflict hazard for consumers when version mismatches arise. Strive for zero external dependencies wherever native Dart core libraries suffice.

The Golden Rule: Information Hiding with lib/src

A major package engineering mistake is exposing internal implementation details in the root lib/ directory. If a consumer imports an internal helper class and you refactor it in a patch release, you have inadvertently caused a breaking change.

Follow the official Dart convention: place all internal classes inside lib/src/. In the root lib/my_package.dart, export ONLY the public API surface that consumers are intended to use. Use the 'show' directive to prevent leaking internal helper types.

Clean public API barrier protects internal classes from accidental consumer coupling
// lib/flutter_devlog.dart (Public API entrypoint)
library flutter_devlog;

// Only export the clean public interface
export 'src/devlog_base.dart' show DevLog;
export 'src/log_level.dart' show LogLevel;
export 'src/log_formatter.dart' show DevLogFormatter;

// Internal implementations like 'src/ansi_color_formatter.dart' remain hidden

Achieving 140/140 Pana Points

Pub.dev ranks packages using Pana, an automated analysis tool. To get a perfect score, your package must meet strict criteria:

  • README.md: Must contain a clear value proposition, installation instructions, usage code snippets, and visual output examples.
  • CHANGELOG.md: Must document every release strictly adhering to Semantic Versioning (MAJOR.MINOR.PATCH).
  • Documentation: Every single public class, method, getter, and parameter must have triple-slash (///) doc comments.
  • Code Quality: Must have zero warnings under flutter_lints and support sound null safety across all target platforms.
  • Example: Must include a working example/ project demonstrating real integration.
  • License: Must include an OSI-approved license like MIT, BSD-3-Clause, or Apache-2.0.

Automating Release Validation with GitHub Actions & OIDC

Never publish a package manually from your personal laptop terminal without automated CI. Set up a GitHub Action that runs dart analyze, dart test, and dart pub publish --dry-run on every pull request.

For production releases, Pub.dev supports automated publishing using OpenID Connect (OIDC) tokens directly from GitHub Actions. This eliminates the security risk of storing personal refresh tokens as repository secrets.

Secure automated package publishing via GitHub Actions with OIDC authentication
name: Publish to Pub.dev

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'

permissions:
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dart-lang/setup-dart@v1
      - run: dart pub get
      - run: dart test
      - name: Publish package
        run: dart pub publish -f

Writing Comprehensive Unit and Golden Tests for Packages

A package without automated tests is an liability for any engineering team considering using it in production. In the Dart ecosystem, package:test provides a fast, headless test runner that executes hundreds of unit tests in seconds.

Write tests that exercise edge cases: null inputs, empty lists, malformed network responses, and boundary condition limits. Aim for minimum 90% code coverage. When Pana analyzes your package on Pub.dev, having an active test suite with 100% passing tests contributes directly to your package ranking and verified publisher trust score.

Managing Community Contributions, Pull Requests, and Deprecations

Once your package gains popularity on Pub.dev, other developers will submit pull requests, report issues, and request features. Having a clear CONTRIBUTING.md guide sets expectations for formatting, branch names, and required test additions.

When deprecating older APIs, never delete symbols abruptly. Use Dart's built-in @Deprecated('Use newMethod() instead in v2.0') annotation. This generates helpful compiler warnings in downstream IDEs, guiding developers to migrate smoothly before the deprecated symbol is removed in the next major version release.

Final Thoughts

Open source is a multiplier for your technical reputation and engineering discipline. Authoring a package forces you to think deeply about API design, backward compatibility, and developer empathy.

Key Takeaways

  • Keep internal implementation code private in lib/src/.
  • Triple-slash doc comments on all public declarations are mandatory for top Pana scores.
  • Always simulate publication with 'dart pub publish --dry-run' before going live.
  • Automate publishing with GitHub Actions and OIDC authentication.
  • Semantic versioning and @Deprecated annotations protect downstream developers.
  • Verified publisher domains build instant credibility and trust across the Flutter community.

Frequently Asked Questions

How does Semantic Versioning work on Pub.dev?

Follow MAJOR.MINOR.PATCH (e.g., 1.2.3). Increment PATCH for backward-compatible bug fixes, MINOR for backward-compatible new features, and MAJOR for any breaking API change. For packages under 1.0.0 (e.g., 0.1.0), incrementing the MINOR version is treated by pub as a breaking change.

How do I test my package before publishing to the public registry?

Run 'dart pub publish --dry-run' in your package directory. It will analyze your package, check for missing files, calculate compressed size, and flag any missing documentation or license issues without uploading anything.

Can I delete a package version if I accidentally publish broken code?

No. Pub.dev policy strictly forbids deleting published package versions to prevent breaking downstream builds. You can, however, mark a version as 'retracted' or publish an immediate patch release (e.g. 1.0.1) fixing the regression.

How do I become a Verified Publisher on Pub.dev?

Create a Google Search Console verified domain (e.g. bayajitislam.com) and link it to your Pub.dev account. Publishing packages under a verified domain gives users confidence and displays a verified badge on your package listing.

What files should be excluded from pub.dev packages?

Add a .pubignore file excluding IDE folders (.idea, .vscode), CI scripts, scratch benchmarks, test coverage reports, and build artifacts to keep package download size small and fast.

Tags:FlutterPub.devOpen SourcePackage DevelopmentDart
Bayajit Islam

Need an AI Mobile App or Scalable Backend?

I'm Bayajit Islam, an AI Mobile App Developer with 2+ years of hands-on experience architecting cross-platform apps for iOS, Android & Desktop with Flutter, paired with high-performance Python & FastAPI backends, streaming LLMs, and DevOps.