Getting Started
Cloud Cache Action allows you to store and retrieve GitHub Actions cache bundles using any S3-compatible cloud or self-hosted object storage service.
It is designed as a drop-in replacement for actions/cache@v4-v6, keeping your CI/CD workflows lightning fast while bypassing GitHub's 10GB default cache quotas and egress fees.
Quickstart
Add the following step to your GitHub Actions workflow:
yaml
- name: Cache dependencies to S3
uses: xSAVIKx/cloud-cache-action@v1
with:
bucket: my-ci-cache-bucket
endpoint: https://<account_id>.r2.cloudflarestorage.com # Or AWS, GCS, B2, MinIO, etc.
access-key: ${{ secrets.S3_ACCESS_KEY }}
secret-key: ${{ secrets.S3_SECRET_KEY }}
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-How It Works
Restore Phase (Pre/Main):
- Connects to your S3 bucket using modern
@aws-sdk/client-s3. - Checks if an exact match exists for the
keyparameter. - If not found, evaluates
restore-keysin order and downloads the most recently updated matching archive. - Decompresses the archive using
zstd(orgzipfallback) directly into your workspace. - Sets outputs (
cache-hit,cache-primary-key,cache-matched-key,cache-size,cache-storage-provider,cache-s3-key).
- Connects to your S3 bucket using modern
Save Phase (Post):
- If
read-only: trueor if an exact key match occurred during restore, saving is automatically skipped. - Otherwise, archives the specified
pathdirectories using multi-threadedzstdcompression. - Streams the compressed archive to your S3 bucket using multipart uploads via
@aws-sdk/lib-storage. - Emits diagnostics and completes cleanly without breaking the build on non-fatal network interruptions.
- If
Standalone Restore and Save Actions
Just like actions/cache/restore and actions/cache/save, you can invoke restore and save as independent steps:
Restore Only
yaml
- name: Restore cache
id: restore-step
uses: xSAVIKx/cloud-cache-action/restore@v1
with:
bucket: my-ci-cache-bucket
key: ${{ runner.os }}-build-${{ hashFiles('**/lock') }}
path: build/Save Only
yaml
- name: Save cache
uses: xSAVIKx/cloud-cache-action/save@v1
with:
bucket: my-ci-cache-bucket
key: ${{ runner.os }}-build-${{ hashFiles('**/lock') }}
path: build/Action Metadata Definitions
You can inspect the full action specification files directly in the repository:
- Unified Action:
action.yml - Dedicated Restore Action:
restore/action.yml - Dedicated Save Action:
save/action.yml
action.yml (Click to view unified action definition)
yaml
name: 'Cloud Cache Action'
description: 'Cache artifacts to any S3-compatible storage with 1:1 actions/cache parity and dual-caching'
author: 'Yurii Serhiichuk (https://serhiichuk.dev)'
inputs:
# Official actions/cache standard inputs
path:
description: 'A list of files, directories, and wildcard patterns to cache and restore'
required: true
key:
description: 'An explicit key for restoring and saving the cache'
required: true
restore-keys:
description: 'An ordered multiline string listing the prefix-matched keys, used for restoring stale cache if no cache hit occurred for key'
required: false
upload-chunk-size:
description: 'The chunk size used to split up large files during upload, in bytes'
required: false
enableCrossOsArchive:
description: 'An optional boolean when enabled, allows windows runners to save or restore caches that can be restored or saved respectively on other platforms'
default: 'false'
required: false
fail-on-cache-miss:
description: 'Fail the workflow if cache entry is not found'
default: 'false'
required: false
lookup-only:
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
default: 'false'
required: false
read-only:
description: 'Restore cache but do not save cache in post step'
default: 'false'
required: false
save-always:
description: 'Run the post step to save the cache even if another step before fails'
default: 'false'
required: false
# S3 Storage inputs
bucket:
description: 'The S3 bucket name where cache archives are stored'
required: true
endpoint:
description: 'Custom S3-compatible endpoint URL (e.g., https://<account_id>.r2.cloudflarestorage.com or https://storage.googleapis.com)'
required: false
region:
description: 'AWS or S3 provider region (e.g., us-east-1, auto, etc.)'
required: false
provider:
description: 'Storage provider preset: aws, r2, gcs, b2, fastly, garage, seaweedfs, minio'
required: false
access-key:
description: 'S3 Access Key ID (falls back to AWS_ACCESS_KEY_ID or IAM/OIDC)'
required: false
accessKey:
description: 'Alias for access-key'
required: false
secret-key:
description: 'S3 Secret Access Key (falls back to AWS_SECRET_ACCESS_KEY)'
required: false
secretKey:
description: 'Alias for secret-key'
required: false
session-token:
description: 'S3 Session Token (falls back to AWS_SESSION_TOKEN)'
required: false
sessionToken:
description: 'Alias for session-token'
required: false
force-path-style:
description: 'Force path-style S3 URLs (bucket in path rather than subdomain)'
required: false
prefix:
description: 'Subfolder prefix path within the bucket'
required: false
default: ''
s3-key-pattern:
description: 'Template pattern for S3 object key. Default: ${GITHUB_REPOSITORY}/${prefix}${key}/${archive_filename}'
required: false
default: '${GITHUB_REPOSITORY}/${prefix}${key}/${archive_filename}'
scoped-to-repository:
description: 'Whether to prefix bucket cache paths with GITHUB_REPOSITORY (default: true)'
required: false
default: 'true'
retry:
description: 'Enable retries with exponential backoff on failure for S3 operations'
required: false
default: 'true'
retry-count:
description: 'Number of times to retry S3 operations in case of failure'
required: false
default: '3'
use-fallback:
description: 'Fall back to official GitHub Actions Cache service if S3 operations fail or miss'
required: false
default: 'false'
# Dual-cache inputs
dual-cache:
description: 'Cache to both S3-compatible storage and GitHub Actions Cache simultaneously'
required: false
default: 'false'
restore-priority:
description: 'Order of cache sources to query during restore: s3-first or github-first'
required: false
default: 's3-first'
dual-cache-strategy:
description: 'Sync strategy for saving in dual-cache mode: backfill (sync missing tier), independent, or skip-on-hit'
required: false
default: 'backfill'
dual-cache-strict:
description: 'Fail step if either tier encounters an error during dual-cache operations (default: false, fault-tolerant)'
required: false
default: 'false'
outputs:
cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key'
cache-primary-key:
description: 'A resolved cache key for which cache match was attempted'
cache-matched-key:
description: 'Key of the cache that was restored, either the primary key or a partial match'
cache-size:
description: 'The size of the restored/saved cache archive in bytes'
cache-storage-provider:
description: 'The resolved S3-compatible storage provider'
cache-s3-key:
description: 'The full S3 object key inside the bucket'
cache-etag:
description: 'The ETag checksum of the cache archive in S3'
cache-hit-source:
description: 'The cache tier that serviced the restore hit: s3, github, or none'
cache-saved-sources:
description: 'Comma-separated list of cache tiers successfully saved to: s3, github, or s3,github'
runs:
using: 'node24'
main: 'dist/restore/index.js'
post: 'dist/save/index.js'
post-if: 'success()'
branding:
icon: 'cloud'
color: 'blue'restore/action.yml (Click to view restore action definition)
yaml
name: 'Restore Cache (S3-Compatible)'
description: 'Restore Cache artifacts from any S3-compatible storage with actions/cache parity'
author: 'Yurii Serhiichuk (https://serhiichuk.dev)'
inputs:
path:
description: 'A list of files, directories, and wildcard patterns to restore'
required: true
key:
description: 'An explicit key for restoring the cache'
required: true
restore-keys:
description: 'An ordered multiline string listing the prefix-matched keys, used for restoring stale cache if no cache hit occurred for key'
required: false
enableCrossOsArchive:
description: 'An optional boolean when enabled, allows windows runners to restore caches that were saved on other platforms'
default: 'false'
required: false
fail-on-cache-miss:
description: 'Fail the workflow if cache entry is not found'
default: 'false'
required: false
lookup-only:
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
default: 'false'
required: false
# S3 Storage inputs
bucket:
description: 'The S3 bucket name where cache archives are stored'
required: true
endpoint:
description: 'Custom S3-compatible endpoint URL'
required: false
region:
description: 'AWS or S3 provider region'
required: false
provider:
description: 'Storage provider preset: aws, r2, gcs, b2, fastly, garage, seaweedfs, minio'
required: false
access-key:
description: 'S3 Access Key ID'
required: false
accessKey:
description: 'Alias for access-key'
required: false
secret-key:
description: 'S3 Secret Access Key'
required: false
secretKey:
description: 'Alias for secret-key'
required: false
session-token:
description: 'S3 Session Token'
required: false
sessionToken:
description: 'Alias for session-token'
required: false
force-path-style:
description: 'Force path-style S3 URLs'
required: false
prefix:
description: 'Subfolder prefix path within the bucket'
required: false
default: ''
s3-key-pattern:
description: 'Template pattern for S3 object key. Default: ${GITHUB_REPOSITORY}/${prefix}${key}/${archive_filename}'
required: false
default: '${GITHUB_REPOSITORY}/${prefix}${key}/${archive_filename}'
scoped-to-repository:
description: 'Whether to prefix bucket cache paths with GITHUB_REPOSITORY (default: true)'
required: false
default: 'true'
retry:
description: 'Enable retries with exponential backoff on failure for S3 operations'
required: false
default: 'true'
retry-count:
description: 'Number of times to retry S3 operations in case of failure'
required: false
default: '3'
use-fallback:
description: 'Fall back to official GitHub Actions Cache service if S3 operations fail or miss'
required: false
default: 'false'
# Dual-cache inputs
dual-cache:
description: 'Cache to both S3-compatible storage and GitHub Actions Cache simultaneously'
required: false
default: 'false'
restore-priority:
description: 'Order of cache sources to query during restore: s3-first or github-first'
required: false
default: 's3-first'
dual-cache-strategy:
description: 'Sync strategy for saving in dual-cache mode: backfill, independent, or skip-on-hit'
required: false
default: 'backfill'
dual-cache-strict:
description: 'Fail step if either tier encounters an error during dual-cache operations'
required: false
default: 'false'
outputs:
cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key'
cache-primary-key:
description: 'A resolved cache key for which cache match was attempted'
cache-matched-key:
description: 'Key of the cache that was restored, either the primary key or a partial match'
cache-size:
description: 'The size of the restored cache archive in bytes'
cache-storage-provider:
description: 'The resolved S3-compatible storage provider'
cache-s3-key:
description: 'The full S3 object key inside the bucket'
cache-etag:
description: 'The ETag checksum of the cache archive in S3'
cache-hit-source:
description: 'The cache tier that serviced the restore hit: s3, github, or none'
runs:
using: 'node24'
main: '../dist/restore-only/index.js'
branding:
icon: 'cloud-download'
color: 'blue'save/action.yml (Click to view save action definition)
yaml
name: 'Save Cache (S3-Compatible)'
description: 'Save Cache artifacts to any S3-compatible storage with actions/cache parity'
author: 'Yurii Serhiichuk (https://serhiichuk.dev)'
inputs:
path:
description: 'A list of files, directories, and wildcard patterns to cache'
required: true
key:
description: 'An explicit key for saving the cache'
required: true
upload-chunk-size:
description: 'The chunk size used to split up large files during upload, in bytes'
required: false
enableCrossOsArchive:
description: 'An optional boolean when enabled, allows windows runners to save caches that can be restored on other platforms'
default: 'false'
required: false
# S3 Storage inputs
bucket:
description: 'The S3 bucket name where cache archives are stored'
required: true
endpoint:
description: 'Custom S3-compatible endpoint URL'
required: false
region:
description: 'AWS or S3 provider region'
required: false
provider:
description: 'Storage provider preset: aws, r2, gcs, b2, fastly, garage, seaweedfs, minio'
required: false
access-key:
description: 'S3 Access Key ID'
required: false
accessKey:
description: 'Alias for access-key'
required: false
secret-key:
description: 'S3 Secret Access Key'
required: false
secretKey:
description: 'Alias for secret-key'
required: false
session-token:
description: 'S3 Session Token'
required: false
sessionToken:
description: 'Alias for session-token'
required: false
force-path-style:
description: 'Force path-style S3 URLs'
required: false
prefix:
description: 'Subfolder prefix path within the bucket'
required: false
default: ''
s3-key-pattern:
description: 'Template pattern for S3 object key. Default: ${GITHUB_REPOSITORY}/${prefix}${key}/${archive_filename}'
required: false
default: '${GITHUB_REPOSITORY}/${prefix}${key}/${archive_filename}'
scoped-to-repository:
description: 'Whether to prefix bucket cache paths with GITHUB_REPOSITORY (default: true)'
required: false
default: 'true'
retry:
description: 'Enable retries with exponential backoff on failure for S3 operations'
required: false
default: 'true'
retry-count:
description: 'Number of times to retry S3 operations in case of failure'
required: false
default: '3'
use-fallback:
description: 'Fall back to official GitHub Actions Cache service if S3 save fails'
required: false
default: 'false'
# Dual-cache inputs
dual-cache:
description: 'Cache to both S3-compatible storage and GitHub Actions Cache simultaneously'
required: false
default: 'false'
dual-cache-strategy:
description: 'Sync strategy for saving in dual-cache mode: backfill, independent, or skip-on-hit'
required: false
default: 'backfill'
dual-cache-strict:
description: 'Fail step if either tier encounters an error during dual-cache save'
required: false
default: 'false'
outputs:
cache-size:
description: 'The size of the saved cache archive in bytes'
cache-storage-provider:
description: 'The resolved S3-compatible storage provider'
cache-s3-key:
description: 'The full S3 object key inside the bucket'
cache-etag:
description: 'The ETag checksum of the cache archive in S3'
cache-saved-sources:
description: 'Comma-separated list of cache tiers successfully saved to: s3, github, or s3,github'
runs:
using: 'node24'
main: '../dist/save-only/index.js'
branding:
icon: 'cloud-upload'
color: 'blue'