AWS S3 Storage
Store your Hot Updater bundles in AWS S3 or any S3-compatible storage service (including Cloudflare R2).
Installation
npm install @hot-updater/aws --save-devFor a custom server, install the runtime dependency in the server project:
npm install @hot-updater/server @hot-updater/awsSetup
For a complete provider deployment, follow the AWS setup. For an existing bucket or a custom server, use the storage configuration below; you do not need to provision the provider's database and server to use this adapter.
Configuration
import type { S3ClientConfig } from "@aws-sdk/client-s3";
interface S3StorageConfig extends S3ClientConfig {
bucketName: string; // S3 bucket name
basePath?: string; // Optional base path within bucket
getDownloadUrl?: (input: { storageUri: string }) => Promise<{ url: string }>;
}The inherited AWS SDK options include region, endpoint, and credentials
(including credential providers and temporary session tokens). If credentials
is omitted, the AWS SDK default credential chain is used. This lets you rely
on local AWS CLI sessions, AWS_PROFILE, shared config files, or other
standard AWS credential sources.
Usage
AWS S3
import { s3Storage } from "@hot-updater/aws";
import { defineConfig } from "hot-updater";
export default defineConfig({
// ... build, database, plugins, and updateStrategy
storage: s3Storage({
region: "us-east-1",
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
bucketName: "my-hot-updater-bucket",
}),
});Cloudflare R2
Use r2Storage for R2, including the
managed Cloudflare Worker. It records r2:// locations that the Worker can
resolve. s3Storage always records s3:// locations, even with an R2 endpoint,
so it requires a server that registers an s3 storage adapter.
Protocol
s3://bucket/encoded/key
For example, s3://my-bucket/releases/1.0.0/bundle%20ios.zip is stored in the
storageUri field. Keys retain their slash hierarchy and encode each segment.
Capabilities
s3Storage implements streaming upload, streaming Web-response reads,
existence checks, exact deletion, and download URLs. A download URL is an S3
presigned URL that expires in an hour, signed with the adapter's credentials:
devices download from the bucket, which stays private. Pass getDownloadUrl
to return another URL instead.
For CloudFront delivery, pass cloudFrontDownloadUrl(...) as getDownloadUrl:
import { cloudFrontDownloadUrl, s3Storage } from "@hot-updater/aws";
const storage = s3Storage({
region: process.env.AWS_REGION!,
bucketName: process.env.AWS_S3_BUNDLES_BUCKET!,
getDownloadUrl: cloudFrontDownloadUrl({
publicBaseUrl: "https://updates.example.com",
keyPairId: process.env.CLOUDFRONT_KEY_PAIR_ID!,
ssmRegion: process.env.AWS_REGION!,
ssmParameterName: process.env.CLOUDFRONT_PRIVATE_KEY_PARAMETER!,
}),
});Use the CloudFront distribution's artifact domain and public key ID. The SSM
parameter stores JSON containing privateKey; grant the server role permission
to read and decrypt it. These settings and the private key remain on the
server. If your secret store is elsewhere, provide
getPrivateKey: async () => privateKeyPem instead of the two SSM options.
Managed AWS initialization configures its CloudFront delivery path for you.
Maintenance
s3Storage provides the object listing and exact deletion capabilities used by
hot-updater storage prune. Follow the Storage Cleanup
guide to remove unreferenced bundle objects and shared assets safely.
Use a separate basePath for every database or environment that shares a
bucket. Pruning assumes that the configured database owns every object below
its storage prefix.
Custom server usage
Use s3Storage with createHotUpdater for self-hosted servers:
import { s3Storage } from "@hot-updater/aws";
import { createHotUpdater } from "@hot-updater/server";
import { apiKeys, insights } from "@hot-updater/server/plugins";
const hotUpdater = createHotUpdater({
database,
plugins: [insights(), apiKeys()],
storage: s3Storage({
region: process.env.AWS_REGION!,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
bucketName: process.env.AWS_S3_BUNDLES_BUCKET!,
}),
// ... other options
});