Amazon S3
S3 uploads and downloads
git clone https://github.com/bijectionhq/s3.git
cd s3
git checkout dbf784d116622da5871f9843073bd75bfc44696aBijection repository access is required. Request access.
Description
S3 uploads and downloads
Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.
Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.
Getting started
- Get the source at the revision above and read its package documentation.
- Check the required Bijection SDK version, dependencies, and external service credentials.
- Follow the package setup instructions and the guide to using components.
- Exercise the component in your deployment according to your project’s verification rules.
Open source
Maintained source: bijectionhq/s3. Based on H4S0/convex-S3-component. License: MIT. Consult the repository for license terms, notices, and contributor attribution.
From the upstream publisher
Convex component for S3-compatible object storage: presigned upload/download URLs and file metadata.
Explore the demo ↗Upstream overview
From the upstream package documentation.
This Convex component integrates Amazon S3 storage by generating presigned URLs that let clients upload and download files directly to/from S3 without proxying through your Convex backend. It provides cache control headers, stable public URLs for CDN integration, and handles AWS SDK v3 authentication. The component exposes actions like generateUploadUrl and getSignedUrl that your frontend can call to get time-limited S3 access URLs.
Use cases
From the upstream package documentation.
- Direct file uploads - Let users upload images, documents, or media files straight to S3 from the browser without hitting your server
- Secure file downloads - Generate time-limited download URLs for private content like user documents or premium assets
- CDN integration - Use stable public URLs with CloudFront or other CDNs for cached static assets with proper cache headers
- Large file handling - Bypass Convex's file size limits by storing large uploads directly in S3 while keeping metadata in Convex
- Asset versioning - Implement cache-busting strategies with versioned object keys and immutable cache headers
How it works
From the upstream package documentation.
The component wraps the AWS SDK v3 S3 client and exposes Convex actions for generating presigned URLs. You configure it by adding AWS credentials and bucket settings to your Convex environment variables, then register it in convex.config.ts using app.use(s3).
The main API includes generateUploadUrl() which returns both a presigned upload URL and a stable public URL, and getSignedUrl() for creating time-limited download links. You can set cache control headers during upload generation and configure response headers like Content-Disposition for downloads.
For production use, the component supports a publicBaseUrl option to point stable URLs at your CloudFront distribution instead of direct S3 URLs. This enables proper CDN caching while keeping the presigned URLs for actual upload/download operations. Your S3 bucket needs CORS configuration to allow direct browser uploads and appropriate IAM permissions for s3:PutObject and s3:GetObject operations.
Upstream package FAQ
What AWS permissions does the Convex S3 Component need?
The component requires IAM permissions for s3:PutObject and s3:GetObject on your S3 bucket. You also need to configure CORS on your bucket to allow direct browser uploads with GET and PUT methods from your allowed origins.
How do I configure a CDN with the Convex S3 Component?
Set the S3_PUBLIC_BASE_URL environment variable to your CloudFront or CDN domain. The Convex S3 Component will use this as the base for stable public URLs instead of the default S3 domain, enabling better caching and performance.
Can I use the Convex S3 Component for private file downloads?
Yes, the Convex S3 Component generates presigned download URLs with configurable expiration times for secure access to private S3 objects. You can also set response headers like Content-Disposition to control how browsers handle the downloaded files.
What's the difference between signed URLs and public URLs in the Convex S3 Component?
The Convex S3 Component returns both signed URLs that expire after a set time and stable public URLs that don't change for a given object key. Stable URLs are better for caching strategies, while signed URLs provide time-limited secure access.
Use with agents and CLI
Give your coding agent the component’s source identity and setup guidance.
Help me integrate Amazon S3 with Bijection.
Read: https://bijection.com/components/s3/SKILL.md
Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.Upstream README.md
View repository ↗Documentation from H4S0/convex-S3-component, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.
@hasoo/convex-s3
A Convex component for integrating Amazon S3 file storage into your Convex backend. It generates presigned upload and download URLs so your clients can talk to S3 directly without proxying files through your server.
Features
- Generate presigned upload URLs for direct-to-S3 uploads
- Generate presigned download URLs for time-limited access
- Set upload cache headers like
Cache-Control - Return a stable object URL alongside the signed upload URL
- Works natively as a Convex component
- Built with the official AWS SDK v3
Prerequisites
- A Convex project
- An AWS account with an S3 bucket
- AWS IAM credentials with
s3:PutObjectands3:GetObjectpermissions
Setup
1. Register the component
In your convex/convex.config.ts:
import { defineApp } from "convex/server";
import s3 from "@hasoo/convex-s3/convex.config.js";
const app = defineApp();
app.use(s3);
export default app;
If you need the packaged component API type in your app:
import type { ComponentApi } from "@hasoo/convex-s3/_generated/component.js";
2. Set environment variables
Add the following environment variables to your Convex dashboard or .env.local:
| Variable | Description |
|---|---|
S3_ACCESS_KEY_ID | Your AWS access key ID |
S3_SECRET_ACCESS_KEY | Your AWS secret access key |
S3_REGION | The AWS region your bucket is in, for example us-east-1 |
S3_BUCKET | The name of your S3 bucket |
S3_PUBLIC_BASE_URL | Optional stable base URL, such as a CloudFront domain |
S3_DEFAULT_CACHE_CONTROL | Optional default Cache-Control header for uploads |
Usage
Generate a presigned upload URL
Use this to let a client upload a file directly to S3 while setting cache headers on the object:
import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";
function UploadButton({ file }: { file: File }) {
const getUploadUrl = useAction(api.s3.generateUploadUrl);
async function handleUpload() {
const key = `uploads/${crypto.randomUUID()}-${file.name}`;
const { url, publicUrl } = await getUploadUrl({
key,
contentType: file.type,
cacheControl: "public, max-age=31536000, immutable",
});
await fetch(url, {
method: "PUT",
body: file,
headers: { "Content-Type": file.type },
});
console.log("Stable object URL:", publicUrl);
}
return <button onClick={handleUpload}>Upload</button>;
}
Generate a presigned download URL
Use this when you need secure, expiring access to a stored file:
const url = await storage.getSignedUrl("uploads/example.png", {
expiresIn: 3600,
responseContentDisposition: 'inline; filename="example.png"',
});
Use stable object URLs for caching
For browser or CDN caching, prefer stable object URLs and versioned object keys:
import { S3Storage } from "@hasoo/convex-s3";
const storage = new S3Storage(component, {
bucket: process.env.S3_BUCKET,
region: process.env.S3_REGION,
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
publicBaseUrl: "https://cdn.example.com",
defaultCacheControl: "public, max-age=31536000, immutable",
});
const { key, publicUrl } = await storage.generateUploadUrl({
key: `assets/${buildHash}/logo.png`,
});
publicUrl stays the same for a given object key, which makes it a much better cache key than a presigned download URL that rotates over time.
AWS IAM Policy
Your IAM user or role needs at least the following permissions on your bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
CORS Configuration
To allow browsers to upload directly to your S3 bucket, configure CORS on the bucket:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT"],
"AllowedOrigins": ["http://localhost:3000", "https://your-production-domain.com"],
"ExposeHeaders": []
}
]
Project Structure
convex-S3-component/
├── convex/
│ ├── convex.config.ts
│ ├── lib.ts
│ ├── schema.ts
│ └── _generated/
├── src/
│ └── client.ts
├── client.ts
├── package.json
└── tsconfig.build.json
The published package builds both the library client entry and the Convex component entrypoints into dist/, including dist/convex/convex.config.js and dist/convex/_generated/component.js.
Dependencies
| Package | Purpose |
|---|---|
@aws-sdk/client-s3 | AWS S3 API client |
@aws-sdk/s3-request-presigner | Presigned URL generation |
convex | Convex backend framework |
Publish Checklist
Before publishing, the usual flow is:
pnpm install
pnpm run typecheck
pnpm run build
pnpm pack
If you want to test the tarball in another project first:
pnpm run pack:local
That gives you a local package archive you can install into a separate Convex app to verify the packaged component entry points before publishing to npm.
License
MIT