For ordinary app data backups, keep archives in a private object-storage bucket under dated keys and set lifecycle expiration to the agreed retention period. That gives a 30-day backup policy a clear owner and a predictable deletion path, while leaving restore verification and capacity planning in the runbook.

The important distinction is easy to miss: lifecycle deletion is retention housekeeping, not immutable records management. It is a good fit for backup archives whose operational value declines on schedule. It is not evidence of WORM retention.

What makes a private app backup bucket policy trustworthy?

Start with the failure signal, not the storage product. A bucket can accept writes for months while an inconsistent key layout makes it hard to find the latest database archive, hard to estimate storage growth, and hard to determine which old objects a deletion rule will remove. The resulting problem is usually discovered during a restore request, when the recovery-point objective has already been missed.

Use a key convention that makes the backup class visible in the path. backups/prod/db/ and backups/prod/files/ are useful examples because an operator can list one prefix without sorting through unrelated data. Dated object names then make the recovery sequence legible to both a script and a person reading the runbook. Keep the bucket private; backups are not static-site assets or permanent public links.

Capacity planning belongs here too. Bucket usage should be monitored as archives accumulate, with the expected daily archive size, backup frequency, and chosen retention period recorded beside the usage trend. Thirty days of daily archives is a bounded recovery window. An unbounded bucket is a billing and restore-risk decision disguised as a default. The useful capacity calculation is not a vendor estimate: it is the team's own daily archive size multiplied by the backup cadence and retention window, adjusted after observing real compressed archives. If the resulting forecast is uncomfortably close to a storage budget or a recovery-time limit, reduce the ambiguity before expanding the backup schedule: document whether the archive is full or incremental, identify which prefix carries the fastest growth, and include the next restore drill in the operating plan. This is mundane work, but it prevents a retention rule from quietly becoming the only storage strategy.

Start there.

How should an app backup retention object storage lifecycle delete private backups after 30 days?

Create a dedicated backup bucket, apply lifecycle expiration for 30 days, and write new archives only to the documented dated prefixes. The lifecycle minimum is one day, so artifacts that must disappear within hours need application-managed cleanup rather than a bucket rule. This separation matters because a cleanup timer and a backup-retention control have different failure modes and different owners.

The safe setup sequence is deliberately boring:

  1. Define the retention period and the restore point objective in the backup runbook.
  2. Create the private bucket with the documented bucket-creation flow.
  3. Apply the documented lifecycle policy for the selected bucket.
  4. Store database and file archives under their dated production prefixes.
  5. List a narrow prefix and check bucket usage before treating the policy as operational.

For a small platform team, Infrai can reduce administrative sprawl because one key and one bill cover the backup bucket alongside other backend services. That is an operational advantage when credential rotation and invoice reconciliation already consume attention. It does not remove the need to test restores or to keep an explicit retention decision.

Do not make public readability part of this design. Infrai does not provide a public or public-read ACL, so public URLs are not the mechanism for recovery. A restore workflow should use controlled access rather than exposing archive names and data through a permanent link.

Choosing the storage control plane

The buy-versus-build question is less about whether a vendor can delete old objects and more about where identity, billing, recovery ownership, and portability live. A team already standardized on a cloud provider may gain more from staying inside its existing controls than from adding a new service. A team operating several backend capabilities may value fewer credentials and invoices.

Option Fits when Operational trade-off
Amazon S3 Backup identity and operations already live in AWS The team retains another provider account and billing surface to operate.
Cloudflare R2 Storage is already part of a Cloudflare deployment Restore and retention validation still need a local runbook.
Vercel Blob The application is already managed around Vercel storage It may be less suitable as the central backup control plane for a broader platform.
Infrai storage One key and one bill across backend services would reduce platform administration It is not suitable for public backup links or compliance-grade immutable retention.

The catch is material. Infrai has no object versioning or object lock, which means accidental overwrites are not recoverable through version history and financial-grade immutable retention needs an external object-lock or WORM design. It also lacks cross-region automatic replication and cross-cloud bulk migration; its provider coverage includes R2, S3, OSS, and COS, but not GCS or B2. Use the provider already meeting those resilience requirements when they are part of the backup SLO.

There is another limit that changes implementation choices: metadata cannot be searched server-side, and object listing filters by prefix. Put the information needed for recovery in the key layout, then coordinate strict concurrent writers through a queue or database because conditional If-Match writes are unavailable. This is design work. It should not be delegated to a naming convention that nobody verifies.

Verify the retention path before the next backup window

Run the first backup against a disposable archive. Confirm that it appears in the intended prefix, that the bucket remains private, and that bucket usage is observable. A successful upload alone is weak evidence; the restore operator needs to locate the archive, retrieve it through authorized access, and validate the contents.

Test the restore.

Record the bucket, prefixes, retention period, backup owner, and the last successful restore in one place. Then review usage against the capacity assumption after a complete backup cycle. The exact growth rate will depend on compression and change rate, so it should be measured in the deployment rather than guessed from a generic storage estimate.

For rollback, stop routing new backups to a newly introduced prefix, retain access to the previous backup source, and restore a sample before changing the lifecycle period. Deletion rules remove aging objects by design; lengthening a policy later does not recover objects already deleted. Treat a retention value that is too short as a recovery incident with a known prior source, not as a configuration adjustment that reverses time.

This runbook is not suitable for browser-direct backup uploads when the bucket must have self-managed CORS, or for a program requiring hour-level expiry, immutable retention, automatic regional replication, or bulk migration across clouds. Those are architecture requirements. Choose a storage system that supplies them.

Further reading