Cache once. Reuse everywhere.
BoringCache is a universal build artifact cache for CI, Docker, and local development. It stores and restores directories you choose so build outputs, dependencies, and tool caches can be reused across environments.
BoringCache does not run builds and is not tied to any build tool. It works with any language, framework, or workflow by caching directories explicitly selected by the user.
Caches are content-addressed and verified before restore. If identical content already exists, uploads are skipped. The same cache can be reused in GitHub Actions, Docker/BuildKit, and on developer machines using the same CLI.
This action caches BuildKit layer caches (the directories used by docker buildx). It does not cache Docker images unless you push them. Caches can be reused outside Docker builds.
- uses: boringcache/docker-action@v1
with:
workspace: my-org/my-project
image: my-app
env:
BORINGCACHE_API_TOKEN: ${{ secrets.BORINGCACHE_API_TOKEN }}Cache is automatically restored before build and saved after.
This action manages a local BuildKit cache directory and a BoringCache tag.
- It restores the cache into a local directory before the build.
- It runs
docker buildxwith cache import/export. - It saves the updated cache back to BoringCache in a post step.
You still control your Dockerfile, build args, and image tags.
Notes:
- If
platformsis set, QEMU is installed viatonistiigi/binfmt. - A
boringcache-builder(docker-container driver) is created for cache export/import. - For direct
buildctlusage, useboringcache/buildkit-actioninstead.
- uses: boringcache/docker-action@v1
with:
workspace: my-org/my-project
image: ghcr.io/${{ github.repository }}
tags: latest,${{ github.sha }}
env:
BORINGCACHE_API_TOKEN: ${{ secrets.BORINGCACHE_API_TOKEN }}- uses: boringcache/docker-action/restore@v1
id: cache
with:
workspace: my-org/my-project
- name: Build with docker buildx
run: |
docker buildx build \
--cache-from=type=local,src=${{ steps.cache.outputs.cache-dir }} \
--cache-to=type=local,dest=${{ steps.cache.outputs.cache-dir }},mode=max \
--load \
-t my-app:latest .
- uses: boringcache/docker-action/save@v1
with:
workspace: my-org/my-project
cache-tag: ${{ steps.cache.outputs.cache-tag }}
cache-dir: ${{ steps.cache.outputs.cache-dir }}- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: boringcache/docker-action@v1
with:
workspace: my-org/my-project
image: ghcr.io/${{ github.repository }}
tags: latest,${{ github.sha }}
push: 'true'
load: 'false'
env:
BORINGCACHE_API_TOKEN: ${{ secrets.BORINGCACHE_API_TOKEN }}- uses: boringcache/docker-action@v1
with:
workspace: my-org/my-project
image: ghcr.io/${{ github.repository }}
platforms: linux/amd64,linux/arm64
push: 'true'
load: 'false'
env:
BORINGCACHE_API_TOKEN: ${{ secrets.BORINGCACHE_API_TOKEN }}This pattern shows how to reuse the same cache across the GitHub Actions runner and a Docker image build.
name: Docker Build (Shared Bundle Cache)
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-22.04
env:
BORINGCACHE_API_TOKEN: ${{ secrets.BORINGCACHE_API_TOKEN }}
BORINGCACHE_WORKSPACE: my-org/my-project
BUNDLE_TAG: bundle
APP_DIR: action/examples/rails_app
steps:
- uses: actions/checkout@v4
# Atomic cache on the runner (same tag reused in the Dockerfile)
- uses: boringcache/action@v1
with:
workspace: ${{ env.BORINGCACHE_WORKSPACE }}
entries: ${{ env.BUNDLE_TAG }}:${{ env.APP_DIR }}/vendor/bundle
- run: |
bundle config set path vendor/bundle
bundle install
working-directory: ${{ env.APP_DIR }}
# Whole-image cache + BuildKit layer cache (BoringCache-backed)
- uses: boringcache/docker-action@v1
with:
workspace: ${{ env.BORINGCACHE_WORKSPACE }}
image: ghcr.io/${{ github.repository }}
tags: latest,${{ github.sha }}
dockerfile: ${{ github.workspace }}/docker/examples/Dockerfile.shared-bundle-cache
context: ${{ env.APP_DIR }}
build-args: |
BORINGCACHE_WORKSPACE=${{ env.BORINGCACHE_WORKSPACE }}
BUNDLE_TAG=${{ env.BUNDLE_TAG }}
secrets: |
id=boringcache_token,env=BORINGCACHE_API_TOKEN# syntax=docker/dockerfile:1.5
FROM ruby:3.3-jammy
ARG BORINGCACHE_WORKSPACE
ARG BUNDLE_TAG=bundle
WORKDIR /app
# Expects Gemfile/Gemfile.lock in the build context root.
COPY Gemfile Gemfile.lock ./
RUN --mount=type=secret,id=boringcache_token \
export BORINGCACHE_API_TOKEN="$(cat /run/secrets/boringcache_token)" && \
curl -sSL https://install.boringcache.com/install.sh | sh && \
boringcache restore "$BORINGCACHE_WORKSPACE" "${BUNDLE_TAG}:/usr/local/bundle" || true && \
bundle config set path /usr/local/bundle && \
bundle install && \
boringcache save "$BORINGCACHE_WORKSPACE" "${BUNDLE_TAG}:/usr/local/bundle"
COPY . .| Input | Required | Default | Description |
|---|---|---|---|
image |
Yes | - | Image name (e.g., my-app or ghcr.io/org/app). |
workspace |
No | repo name | Workspace in org/repo form. Defaults to BORINGCACHE_DEFAULT_WORKSPACE or repo name. |
context |
No | . |
Build context path. |
dockerfile |
No | Dockerfile |
Dockerfile path. |
tags |
No | latest |
Image tags (comma-separated). |
build-args |
No | - | Build arguments (newline-separated). |
secrets |
No | - | Build secrets (newline-separated). |
target |
No | - | Target build stage. |
platforms |
No | - | Target platforms (enables QEMU). |
push |
No | false |
Push to registry. |
load |
No | true |
Load into local daemon. Ignored when platforms is set. |
no-cache |
No | false |
Build without cache. |
cache-mode |
No | max |
BuildKit cache mode (min or max). |
cache-tag |
No | slugified image name | Cache tag for BoringCache. |
cli-version |
No | v1.0.0 |
BoringCache CLI version. Set to skip to disable installation. |
buildx-version |
No | - | Buildx version to use (e.g., v0.12.0, latest). |
driver |
No | docker-container |
Buildx driver. |
driver-opts |
No | - | Driver options (newline-separated). |
buildkitd-config-inline |
No | - | Inline BuildKit daemon config (TOML). |
| Output | Description |
|---|---|
image-id |
Image ID |
digest |
Image digest |
cache-hit |
Whether cache was restored |
buildx-name |
Name of the buildx builder |
buildx-platforms |
Available platforms |
Platform scoping is what makes it safe to reuse caches across machines.
By default, caches are isolated by OS and architecture. For multi-platform builds, QEMU is installed automatically when platforms is set.
| Variable | Description |
|---|---|
BORINGCACHE_API_TOKEN |
API token for BoringCache authentication |
BORINGCACHE_DEFAULT_WORKSPACE |
Default workspace if not specified in inputs |
- Cache not restored: ensure
BORINGCACHE_API_TOKENis set and the workspace exists. - No cache files to save: the BuildKit cache directory may be empty on the first run.
- Multi-platform build errors: verify the runner supports QEMU and use
push: trueinstead ofload.
See https://github.com/boringcache/docker-action/releases.
MIT