Packages, pubspec and project layout
Write a pubspec, manage version constraints and lock files, structure a package, and know what publishing requires.
The pubspec
name: shop_core
description: Domain models and pricing rules for the shop.
version: 0.3.0
repository: https://github.com/example/shop_core
publish_to: none # remove this line to publish to pub.dev
environment:
sdk: ^3.5.0 # a caret constraint: 3.5.0 up to but not including 4.0.0
dependencies:
collection: ^1.19.0
http: ^1.2.0
meta: ^1.15.0
dev_dependencies:
lints: ^5.0.0
test: ^1.25.0
build_runner: ^2.4.0
dependency_overrides:
# temporary: force one version while waiting for an upstream fix
collection: 1.19.0dart pub get # resolve and write pubspec.lock
dart pub upgrade # move to the newest allowed versions
dart pub upgrade --major-versions
dart pub outdated # what is behind, and whether it is safe to move
dart pub add http # edit the pubspec and resolve
dart pub deps --style=compact
dart pub publish --dry-run # validate before publishing
dart pub cache repair # fix a corrupted package cache| Constraint | Means | Use for |
|---|---|---|
^1.2.3 | >=1.2.3 <2.0.0 | The default for a library |
>=1.2.3 <2.0.0 | Explicit range | When a caret is not what you mean |
any | No constraint | Almost never; it breaks resolution |
1.2.3 | Exactly that version | A temporary override |
git: block | A git dependency | An unreleased fix, pinned to a ref |
path: block | A local directory | A monorepo or local development |
- Commit
pubspec.lockfor an application so every machine and CI run resolves the same versions. Do not commit it for a library, where consumers must be free to resolve their own graph. - A caret constraint on a
0.xversion treats the minor as breaking:^0.3.0means>=0.3.0 <0.4.0, not<1.0.0. dependency_overrideschanges resolution for the whole package graph and should be temporary. It hides the conflict rather than fixing it.- Prefer a git dependency pinned to a commit hash over a branch. A branch moves and your build becomes non-reproducible.
Layout and visibility
shop_core/
pubspec.yaml
analysis_options.yaml
README.md
CHANGELOG.md
lib/
shop_core.dart # the public API: exports only what consumers need
src/ # everything else is private by convention
money.dart
pricing.dart
internal/
rounding.dart
test/
money_test.dart
pricing_test.dart
example/
main.dart # compiled by pub.dev and by the analyzer
tool/
generate.dart # scripts, not part of the published package// lib/shop_core.dart — the public surface
/// Pricing rules and domain models for the shop.
library;
export 'src/money.dart' show Money;
export 'src/pricing.dart' show PricingRule, applyRules;
// src/internal/rounding.dart is deliberately not exported.
// Because everything outside lib/src is importable by convention,
// dart's linter warns when a consumer imports package:shop_core/src/...
// The src/ directory is the community agreement for "private to this package".# analysis_options.yaml — the strongest cheap quality gate
include: package:lints/recommended.yaml
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
invalid_annotation_target: ignore
todo: ignore
linter:
rules:
- prefer_final_locals
- avoid_print
- unawaited_futures
- always_declare_return_typesPublishing rules
- A published version is immutable. Increasing the version and publishing again is the only way to fix a mistake, so run
--dry-runevery time. - Follow semantic versioning. A breaking change in a
1.xlibrary means2.0.0, and consumers need a changelog entry that names the change. - Every public declaration needs a doc comment, and every package needs a
README.mdand aCHANGELOG.mdwith an entry for the version being published. The publisher rejects a package without them. - Keep the dependency list small. Each dependency is a constraint you impose on every consumer's resolution.
- Do not publish secrets or generated files. Check
.pubignoreor.gitignoreand read the file list in the dry run output.
💡
Run
dart pub publish --dry-run in CI. It validates the layout, the version constraint, the changelog and the analysis, and it catches the missing doc comment that would otherwise fail at the moment you are trying to ship a release.FAQ
Why does resolution fail with a version conflict?
Two packages in the graph need incompatible versions of a third. Run
dart pub deps and dart pub outdated to see who constrains what, then widen your own constraint or upgrade the package that is behind. Reach for dependency_overrides last.Should I use build_runner?
Only when the generated code earns its keep: JSON serialisation for many models, a database layer, or code generation for a routing table. It adds a build step, a cache to clean and a version to keep in step with the source.
Related
Testing Dart code Command-line tools: args, stdin and exit codes
Last refreshed 2026-09-18.