documentation

CI Integration

Automatically track bundle sizes on every push

Environment variables

Add your API token as a CI secret named DENDROBUNDLE_TOKEN. Never commit the raw token value.

The push endpoint accepts two optional query parameters:

Parameter Description
branch Branch name (e.g. main, feat/new-header)
commit Full 40-character commit SHA

Both are optional but strongly recommended — without them, dendrobundle can't diff snapshots across branches. Full parameter and header documentation: API Reference.

GitHub Actions

name: CI

on:
  push:
    branches: ['**']
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - run: npm ci

      - run: npm run build

      - name: Push bundle stats
        env:
          DENDROBUNDLE_TOKEN: ${{ secrets.DENDROBUNDLE_TOKEN }}
        run: |
          curl -sS \
            "https://dendrobundle.com/api/push?branch=${GITHUB_REF_NAME}&commit=${GITHUB_SHA}" \
            -H "Authorization: Bearer $DENDROBUNDLE_TOKEN" \
            -H "Content-Type: application/json" \
            -d @dist/webpack-stats.json

GITHUB_REF_NAME and GITHUB_SHA are provided by Actions automatically — no manual extraction needed.

Large stats files (multi-MB): gzip the body — gzip -c dist/webpack-stats.json | curl … -H "Content-Encoding: gzip" --data-binary @-. The server inflates it transparently (decompressed limit 150 MB). See the API reference.

GitHub PR checks (commit status + comment)

On top of recording the snapshot, dendrobundle can post the size result back to the pull request — a commit status (pass/fail against your budget) and a comment with the per-asset diff — so the bundle signal lands where review happens.

Add three push parameters and one header to the push step:

Param / header Value
gh_repo (query) owner/name — the GitHub repository
commit (query) the full commit SHA (use the PR head SHA on pull-request builds)
pr (query) the pull-request number — omit to post only the commit status
x-github-token (header) a token with statuses:write + pull_requests:write

In GitHub Actions the built-in GITHUB_TOKEN already has those scopes once you grant them under permissions:. It is short-lived and is never stored by dendrobundle.

name: CI

on:
  pull_request:

permissions:
  contents: read
  statuses: write
  pull-requests: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - run: npm ci

      - run: npm run build

      - name: Push bundle stats + PR check
        env:
          DENDROBUNDLE_TOKEN: ${{ secrets.DENDROBUNDLE_TOKEN }}
        run: |
          curl -sS \
            "https://dendrobundle.com/api/push?branch=${GITHUB_HEAD_REF}&commit=${{ github.event.pull_request.head.sha }}&gh_repo=${{ github.repository }}&pr=${{ github.event.pull_request.number }}" \
            -H "Authorization: Bearer $DENDROBUNDLE_TOKEN" \
            -H "x-github-token: ${{ github.token }}" \
            -H "Content-Type: application/json" \
            -d @dist/webpack-stats.json

On pull_request events use github.event.pull_request.head.sha for commit — the built-in GITHUB_SHA points at the temporary merge commit, so the status would attach to the wrong SHA and never show on the PR.

The PR feedback is best-effort: if GitHub is unreachable or the token lacks scope, the snapshot is still recorded and the push still succeeds. (Prefer zero token wiring? The dendrobundle GitHub App posts the same result as a native check run once installed — no per-push token needed.)

GitLab CI

stages:
  - build
  - push

build:
  stage: build
  image: node:20
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/

push-bundle:
  stage: push
  image: curlimages/curl:latest
  dependencies:
    - build
  script:
    - |
      curl -sS \
        "https://dendrobundle.com/api/push?branch=${CI_COMMIT_REF_NAME}&commit=${CI_COMMIT_SHA}" \
        -H "Authorization: Bearer $DENDROBUNDLE_TOKEN" \
        -H "Content-Type: application/json" \
        -d @dist/webpack-stats.json
  variables:
    DENDROBUNDLE_TOKEN: $DENDROBUNDLE_TOKEN

Add DENDROBUNDLE_TOKEN to Settings → CI/CD → Variables in your GitLab project. Mark it as masked.

CircleCI

version: 2.1

jobs:
  build:
    docker:
      - image: cimg/node:20.11
    steps:
      - checkout
      - run: npm ci
      - run: npm run build
      - run:
          name: Push bundle stats
          command: |
            curl -sS \
              "https://dendrobundle.com/api/push?branch=${CIRCLE_BRANCH}&commit=${CIRCLE_SHA1}" \
              -H "Authorization: Bearer $DENDROBUNDLE_TOKEN" \
              -H "Content-Type: application/json" \
              -d @dist/webpack-stats.json

workflows:
  ci:
    jobs:
      - build

Add DENDROBUNDLE_TOKEN under Project Settings → Environment Variables. CIRCLE_BRANCH and CIRCLE_SHA1 are built in.

Per-file format selection

The push endpoint auto-detects the format by inspecting the JSON structure. If you generate multiple stat formats in one build, pick the one with the most detail:

# webpack-stats gives module-level resolution — use this when available
curl -sS "https://dendrobundle.com/api/push?branch=$BRANCH&commit=$SHA" \
  -H "Authorization: Bearer $DENDROBUNDLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d @dist/webpack-stats.json

# esbuild metafile is the second-best option
curl -sS "https://dendrobundle.com/api/push?branch=$BRANCH&commit=$SHA" \
  -H "Authorization: Bearer $DENDROBUNDLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d @dist/meta.json

Failure handling

A non-200 response from the push endpoint means the snapshot was not recorded. The curl exit code will be non-zero, which will fail the CI step. If you want a failed upload to be non-blocking, append || true:

curl -sS ... -d @dist/webpack-stats.json || true

README badge

Every project has a live SVG badge showing its latest bundle size. The badge is public, cached, and turns red when the project is over budget. Drop this into your README (find the copy-paste snippet under Project → Settings → README badge):

[![bundle size](https://dendrobundle.com/api/badge/YOUR_PROJECT_SLUG)](https://dendrobundle.com/p/YOUR_PROJECT_SLUG)

An unknown slug renders a neutral placeholder rather than an error, so a badge never breaks a README.