Private Pub

Docs

Set up Private Pub

Pub needs your token on every machine that publishes or installs your packages. Start with the basic setup, then follow the guides for your editor, your agents and your CI.

For agents and LLMs: this page as markdown or llms.txt

Start here

Basic setup

Do this once on each computer that publishes or installs your packages. Flutter reads the same tokens as Dart, so it covers flutter pub too.

  1. 1

    Get your token

    Create an account or sign in, then create a token. It stays hidden on the account page until you show it, and you can come back later to copy it again.

  2. 2

    Add it to pub

    Run this and paste the token when pub asks for it. Pub saves it and sends it with every request to this server.

    Terminal
    dart pub token add https://private-pub.dev

    Run dart pub token list to check that it was saved.

  3. 3

    Publish a package

    Set publish_to in the package's pubspec.yaml, then publish it as usual. It starts in your personal team, so only its members can see it, unless an optional private_pub.team names another team you can publish to. The server checks every upload the way pub.dev does, and the package requirements list what it looks for.

    pubspec.yaml
    name: my_package
    description: A short sentence about what the package does.
    version: 1.0.0
    publish_to: https://private-pub.dev
    Terminal
    dart pub publish
  4. 4

    Install packages

    Choose how your apps get packages. Both ways use the token you added.

    Mirror

    Everything through this server

    Set PUB_HOSTED_URL and every dependency comes from here, your packages and pub.dev packages alike. Add it to your shell profile, such as ~/.zshrc, so every terminal gets it.

    export PUB_HOSTED_URL=https://private-pub.dev
    Per dependency

    Only the dependencies you choose

    Mark the dependencies that should come from this server with hosted, and the rest keep coming straight from pub.dev.

    dependencies:
      my_package:
        hosted: https://private-pub.dev
        version: ^1.0.0

    To add a private package from the command line, name this server with it. In a Flutter app, run flutter pub add instead.

    Terminal
    dart pub add 'my_package:{"hosted":"https://private-pub.dev"}'

    If a project uses the mirror, set PUB_HOSTED_URL everywhere pub runs for it, including your editor, your agents and CI. The guides below show how.

Editor

VS Code

The Dart and Flutter extensions run pub with your SDK, so they use the token from the basic setup. Dependencies marked with hosted need nothing else.

Use the mirror

If you export PUB_HOSTED_URL in your shell profile, restart VS Code so it picks the variable up. To set it for one project and share it with your team, put it in the workspace settings instead. The file holds no secrets, so commit it.

.vscode/settings.json
{
  "dart.env": {
    "PUB_HOSTED_URL": "https://private-pub.dev"
  },
  "terminal.integrated.env.osx": {
    "PUB_HOSTED_URL": "https://private-pub.dev"
  },
  "terminal.integrated.env.linux": {
    "PUB_HOSTED_URL": "https://private-pub.dev"
  },
  "terminal.integrated.env.windows": {
    "PUB_HOSTED_URL": "https://private-pub.dev"
  }
}

dart.env covers the pub commands the extensions run, like the one after you save pubspec.yaml. The terminal settings cover the commands you type in the integrated terminal, once you trust the workspace.

If you added the token with --env-var, pub reads it from that variable every time it runs, so VS Code has to see the variable too. On your own computer, a plain dart pub token add is simpler.

Agents

Claude Code and other agents

Agents run pub in a shell, so they need what your terminal needs: your token, and PUB_HOSTED_URL if you use the mirror. They also need to know which packages live here.

Claude Code on your computer

Claude Code runs commands as you, so it uses the token you already added.

To use the mirror, set PUB_HOSTED_URL in the project's settings. Every command Claude runs gets it, and cloud sessions read the same file. With sandboxing on, Claude Code asks before a command reaches a new domain. Allow private-pub.dev up front so pub never waits on the prompt.

.claude/settings.json
{
  "env": {
    "PUB_HOSTED_URL": "https://private-pub.dev"
  },
  "sandbox": {
    "network": {
      "allowedDomains": ["private-pub.dev"]
    }
  }
}

Claude Code on the web

Cloud sessions start on a fresh machine without Dart, Flutter or your token. Set them up in the cloud environment settings at claude.ai/code.

On Pro and Max plans, add an API credential with private-pub.dev under Allowed websites and your token as the Authorization header, with the Bearer prefix. The proxy adds it to every request to this server, so the token never reaches the session and pub needs no setup.

On other plans, add PRIVATE_PUB_TOKEN under Environment variables. Anyone who uses the environment can read it, so keep it in a personal environment, not a shared one. Set Network access to Custom, add private-pub.dev to Allowed domains, and check Also include default list of common package managers so pub.dev still works.

Either way, install Dart or Flutter in the Setup script. With the environment variable, add the token to pub there too.

Setup script
#!/bin/bash
set -e
# Install Dart or Flutter here, then:
dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN

Tell the agent where packages come from

Unless the project uses the mirror, a plain dart pub add looks for packages on pub.dev. Say where private packages live in CLAUDE.md, or in AGENTS.md for other agents.

CLAUDE.md
## Private packages

Private packages are hosted on https://private-pub.dev. Add one with:

```sh
dart pub add 'package_name:{"hosted":"https://private-pub.dev"}'
```

See https://private-pub.dev/llms.txt for how to use the server.

Other agents and cloud machines

Codex, Cursor, GitHub Codespaces and anything else that runs on a machine of its own work the same way. Store a service account token as a secret environment variable and add it to pub with --env-var before pub get. A personal token is fine on a machine only you use. The machine also needs to reach private-pub.dev.

Terminal
dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN
CI

GitHub Actions

In CI, pub reads the token from an environment variable, so it never goes in the repository.

  1. 1

    Add the token as a secret

    In the repository on GitHub, open Settings, then Secrets and variables, then Actions. Add a repository secret called PRIVATE_PUB_TOKEN with a service account token.

    Create a service account and add it to every team the job needs, as a reader to install or a writer to publish. One token reaches all of those teams, so CI never needs your own token, which can publish every package you can. A team key still works for a single team. The teams guide covers service accounts.

  2. 2

    Add it to pub before pub get

    Set the secret for the whole job, not just one step, because pub reads it every time it runs.

    .github/workflows/ci.yaml
    name: CI
    
    on: [push, pull_request]
    
    jobs:
      build:
        runs-on: ubuntu-latest
        env:
          PRIVATE_PUB_TOKEN: ${{ secrets.PRIVATE_PUB_TOKEN }}
          PUB_HOSTED_URL: https://private-pub.dev # Only if you use the mirror
        steps:
          - uses: actions/checkout@v6
          - uses: dart-lang/setup-dart@v1
          - run: dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN
          - run: dart pub get
          - run: dart test

    For a Flutter app, set up Flutter instead and run the flutter commands:

    .github/workflows/ci.yaml
        steps:
          - uses: actions/checkout@v6
          - uses: subosito/flutter-action@v2
            with:
              channel: stable
          - run: dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN
          - run: flutter pub get
          - run: flutter test

    Workflows run for pull requests from forks don't get your secrets, and neither do the ones Dependabot starts. If Dependabot updates this project, add PRIVATE_PUB_TOKEN as a Dependabot secret too.

    Very Good Workflows run pub get before their setup input, so they can't add the token in time. Use a job like this one for projects with private dependencies.

  3. 3

    Publish from CI

    Run dart pub publish --force, which skips the confirmation prompt. This workflow publishes whenever you push a version tag.

    .github/workflows/publish.yaml
    name: Publish
    
    on:
      push:
        tags: ['v*']
    
    jobs:
      publish:
        runs-on: ubuntu-latest
        env:
          PRIVATE_PUB_TOKEN: ${{ secrets.PRIVATE_PUB_TOKEN }}
        steps:
          - uses: actions/checkout@v6
          - uses: dart-lang/setup-dart@v1
          - run: dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN
          - run: dart pub publish --force
CI

Codemagic

Codemagic keeps the token in a secret environment variable, and your workflow adds it to pub before getting packages.

  1. 1

    Add the token to Codemagic

    Open the app's settings in Codemagic and go to the Environment variables tab. Add a variable named PRIVATE_PUB_TOKEN with a service account token as its value, put it in a group called private_pub, select Secret and click Add.

  2. 2

    Add it to pub before getting packages

    With codemagic.yaml, import the group and add the token before flutter pub get. Codemagic runs each script in a shell of its own, so set PUB_HOSTED_URL under vars, not with export.

    codemagic.yaml
    workflows:
      build:
        name: Build
        environment:
          flutter: stable
          groups:
            - private_pub
          vars:
            PUB_HOSTED_URL: https://private-pub.dev # Only if you use the mirror
        scripts:
          - name: Add the Private Pub token
            script: dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN
          - name: Get packages
            script: flutter pub get
          - name: Test
            script: flutter test

    With the Workflow Editor, add the token command to the Post-clone script, which runs before Codemagic installs dependencies. To use the mirror, also add PUB_HOSTED_URL on the Environment variables tab.

    Post-clone script
    #!/bin/sh
    set -e
    dart pub token add https://private-pub.dev --env-var PRIVATE_PUB_TOKEN