Skip to content
use-cases / ci-cache-without-s3 / hero
FILES · CACHE · COST-OPTIMIZE

The CI cache that's not an S3 line item

Most CI pipelines burn money on cache traffic — push artifacts to S3, pull them back next job, pay for storage, pay for egress, pay again when runners shift region. On Hoody the cache is a folder on the same bare metal that runs your build container. Push a tarball with curl. Pull it with curl. The bytes never leave the box.

Read the Files API
use-cases / ci-cache-without-s3 / mechanism

Three curls and a cron

The whole CI cache is three commands and one cleanup job. PUT to write a tarball. GET to read it. find -atime to prune. There is no fourth piece — no IAM policy, no bucket lifecycle, no signed URL ceremony.

WRITE

Compress and PUT

After install, the runner streams node_modules through tar | zstd into a single PUT against /files/cache. Hoody writes the body to disk as one binary blob. No multipart, no part-uploader, no SDK.

# After yarn install, push the artifacttar c node_modules | zstd -T0 | curl -T - https://files.containers.hoody.com/cache/$KEY.tar.zst
READ

GET and untar

The next job's first step is one curl. The body comes off NVMe at line rate because the cache lives on the same physical box as the runner — no egress hop, no cross-AZ pull, no CloudFront edge.

# Next job: pull and untar in one linecurl -fsS https://files.containers.hoody.com/cache/$KEY.tar.zst | tar x -I zstd
PRUNE

find -atime · nightly

Hoody Cron fires once a night. find /files/cache -atime +30 -delete throws out anything no job has read in a month. No retention policy, no Glacier tier, no lifecycle JSON to maintain.

# Nightly cron — anything unread in 30d is gonefind /files/cache -atime +30 -delete

PUT writes. GET reads. find prunes. The Hoody Files API is the cache server, the cleanup engine, and the audit log — all behind the same /files/[path] URL.

use-cases / ci-cache-without-s3 / powers

Three powers of cache-as-folder

Pushing the cache out to a separate vendor used to make sense when storage was scarce. On a bare-metal container, it just adds a vendor.

ECONOMICS

No GB-month, no egress, no requests

S3 charges three meters: storage, egress, and per-request. Hoody Files is included in the flat-rate server price — the disk you already rent is the disk the cache sits on. The bytes never cross a billing boundary.

LATENCY

NVMe instead of cross-region

Reads come off the same physical box that runs the build. There is no S3 endpoint to resolve, no TLS handshake to a region, no rate limit on prefix throughput. A 1.4 GB Rust target unpacks in seconds.

OWNERSHIP

One vendor relationship, not two

Your runner and your cache live on the same instance, billed on the same invoice, debugged with the same SSH session. When you turn the container off, the cache is the disk image — back online the moment you boot it.

use-cases / ci-cache-without-s3 / invoice

What evaporates from the bill

A typical mid-size CI footprint moves about 1.4 TB of cache traffic per month. Here is the line item it builds on AWS; on Hoody the cache runs inside the flat-rate server you already pay for.

BEFORE · S3 INVOICEthis month, on AWS
  • Storage · GB-month$1.0947.2 GB × $0.023
  • Egress · GB out$127.801.42 TB × $0.090
  • PUT requests$2.06412k × $5/M
  • GET requests$4.5611.4M × $0.40/M
  • CloudFront / NAT−$57.71cross-AZ pull
monthly total$78
five line items · five rates · one bucket
AFTER · HOODY FILESthis month, on Hoody
  • Disk on the serverno extra chargecovered by the flat monthly server price
  • Egress between jobsno extra chargeloopback · stays on the box
  • PUT / GET requestsno per-request or per-GB meterno per-request meter
  • Vendor relationshipno extra chargethe runner and the cache are one invoice
  • 47.2 GB usedof planheadroom on the same server disk you already rent
monthly totalincluded in server price
one disk · one bill · zero new vendor

When the cache lives on the box that runs the build, the meter S3 was running has nothing to read. The line item doesn't move because there is no transaction to bill.

use-cases / ci-cache-without-s3 / capacity

What the Files endpoint guarantees

Hoody Files isn't a thin wrapper — it's a real persistent backend with hashing, history, range reads, and an audit journal. The CI cache uses a thin slice of what's actually exposed.

  1. ONE URL · ANY ARTIFACT/files/[path]

    PUT to write, GET to read, HEAD for ETag and Content-Length, ?hash for SHA256, ?stat for metadata. The cache is the same endpoint family that powers logs, builds, and shared artifacts.

  2. TIME-TRAVEL READS?at · ?revision

    Every write goes through the file journal. Pull yesterday's cache by timestamp or by per-path revision number — debugging a flake stops requiring a separate snapshot tool.

  3. MOUNT WHEN YOU OUTGROW IT60+ backends

    If the cache really does need to live in S3, B2, or a Drive folder, mount it as a backend and keep the same /files/[path] URL. The runner code never changes — the cache just moves.

Numbers reflect the published Hoody Files API surface — `GET/PUT/HEAD/PATCH /api/v1/files/[path]`, the `?hash`/`?stat`/`?at`/`?revision`/`?history` query parameters, and the file journal endpoints under `/api/v1/journal`.

use-cases / ci-cache-without-s3 / punchline

Your CI cache stops being a separate vendor. It's a folder on the box you already rent.

yesterday · five ratestoday · one disk
WHAT THE OLD BILL HADS3 bucket + egress + requests + lifecyclefive line items · separate IAM · separate vendor
WHAT IT IS NOWPUT /files/cache/$KEY · GET /files/cache/$KEYtwo curls — and the cache is the runner's own disk
Read the Files spec
use-cases / ci-cache-without-s3 / replaces

What this replaces

The standard reach-for-it cache backends each charge you a vendor relationship, an egress bill, or a per-build fee. /files charges you none of those.

  • AWS S3 bucket-as-cacheStorage, egress, requests — three meters for a tarball you keep two days
  • GitHub Actions cache10 GB free, then per-GB fees and a 7-day eviction you can't tune
  • BuildJet cachePer-runner pricing for storage that lives off the runner anyway
  • Bazel remote cache servicesA whole second daemon and a cache protocol to babysit
  • Turborepo Remote CachePer-build pricing for a tarball your monorepo already produced
  • Earthly Cloud cacheA managed remote backend for what is just curl + tar
use-cases / ci-cache-without-s3 / cta

Stop renting a cache from a second cloud. Write the tarball to the disk you already pay for, and curl it back.

Read the Files API
use-cases / ci-cache-without-s3 / related

Read the others