CI/CD Integration
club integrates cleanly with CI/CD pipelines. The basic recipe is:
- Create a Personal Access Token (PAT) scoped to exactly what the job needs.
- Store it as a CI secret (e.g.
CLUB_TOKEN). - Register it with
dart pubusing--env-varso the token never touches disk. - Run
dart pub get,dart pub publish, orclub publishas usual.
Creating CI Tokens
Create a dedicated PAT from the web UI at /settings/keys with the minimum scopes:
| Job type | Scopes |
|---|---|
Read-only (build, test, dart pub get) | read |
Publishing (dart pub publish, club publish) | read + write |
Optionally set an expiry (e.g. 90 days) so forgotten keys don’t linger. The full secret (club_pat_...) is shown once — copy it straight into your CI provider’s secrets store.
dart pub token add --env-var
The --env-var flag registers a token by environment variable name — the token itself is not written to disk. At resolution time dart pub reads the named env var:
dart pub token add https://club.example.com --env-var CLUB_TOKENWith CLUB_TOKEN exported to the value club_pat_..., dart pub get and dart pub publish will attach it as a Bearer token automatically.
GitHub Actions
Fetching Packages
name: Buildon: [push, pull_request]
jobs:build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dart-lang/setup-dart@v1
- name: Configure club token run: dart pub token add https://club.example.com --env-var CLUB_TOKEN env: CLUB_TOKEN: ${{ secrets.CLUB_TOKEN }}
- name: Get dependencies run: dart pub get env: CLUB_TOKEN: ${{ secrets.CLUB_TOKEN }}
- name: Run tests run: dart testPublishing Packages
name: Publishon:push: tags: - 'v*'
jobs:publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dart-lang/setup-dart@v1
- name: Configure club token run: dart pub token add https://club.example.com --env-var CLUB_TOKEN env: CLUB_TOKEN: ${{ secrets.CLUB_TOKEN }}
- name: Publish package run: dart pub publish --force env: CLUB_TOKEN: ${{ secrets.CLUB_TOKEN }}Flutter Projects
name: Flutter Buildon: [push, pull_request]
jobs:build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: flutter-version: '3.x'
- name: Configure club token run: dart pub token add https://club.example.com --env-var CLUB_TOKEN env: CLUB_TOKEN: ${{ secrets.CLUB_TOKEN }}
- name: Get dependencies run: flutter pub get env: CLUB_TOKEN: ${{ secrets.CLUB_TOKEN }}
- name: Run tests run: flutter testGitLab CI
stages:- build- publish
variables:CLUB_SERVER: https://club.example.com
build:image: dart:stablestage: buildbefore_script: - dart pub token add $CLUB_SERVER --env-var CLUB_TOKENscript: - dart pub get - dart testcache: key: dart-packages paths: - .dart_tool/
publish:image: dart:stablestage: publishonly: - tagsbefore_script: - dart pub token add $CLUB_SERVER --env-var CLUB_TOKENscript: - dart pub publish --forceBitbucket Pipelines
image: dart:stable
pipelines:default: - step: name: Build and Test caches: - dart-packages script: - dart pub token add https://club.example.com --env-var CLUB_TOKEN - dart pub get - dart test
tags: 'v*': - step: name: Publish script: - dart pub token add https://club.example.com --env-var CLUB_TOKEN - dart pub publish --force
definitions:caches: dart-packages: .dart_tool/CircleCI
version: 2.1
jobs:build: docker: - image: cimg/dart:stable steps: - checkout - run: name: Configure club token command: dart pub token add https://club.example.com --env-var CLUB_TOKEN - run: dart pub get - run: dart test
publish: docker: - image: cimg/dart:stable steps: - checkout - run: name: Configure club token command: dart pub token add https://club.example.com --env-var CLUB_TOKEN - run: dart pub publish --force
workflows:test-and-publish: jobs: - build - publish: requires: - build filters: tags: only: /^v.*/ branches: ignore: /.*/Caching Strategies
Caching Dart dependencies speeds up CI builds significantly:
| Directory | Contents |
|---|---|
.dart_tool/ | Resolved package config and cached build artifacts |
~/.pub-cache/ | Downloaded package archives |
GitHub Actions Caching
- name: Cache Dart packages uses: actions/cache@v4 with: path: | ~/.pub-cache .dart_tool/ key: dart-${{ hashFiles('pubspec.lock') }} restore-keys: | dart-GitLab CI Caching
cache: key: dart-$CI_COMMIT_REF_SLUG paths: - .dart_tool/ - $PUB_CACHESecurity Best Practices
-
Use minimal scopes. Read-only build jobs should use
readonly. Addwriteonly for publish jobs. -
Set an expiry. Short-lived tokens (e.g. 90 days) limit the blast radius of a leak.
-
Always use
--env-var. Never hardcode tokens in pipeline files, Dockerfiles, or committed scripts. -
Mark secrets as masked. All major CI providers support masking secrets in logs.
-
Separate read and write tokens. One token for build jobs (read-only), another for publish jobs (read + write).
-
Revoke promptly. When a pipeline is decommissioned or a developer leaves, revoke the associated PATs from
/settings/keys.