Skip to main content

Serving Files

Files can be served privately (through a server endpoint) or publicly (direct S3 URL).

Private Files

Create a SvelteKit endpoint that streams files through the server. This allows access control:

// routes/files/[fileId]/+server.ts
import type { RequestHandler } from './$types'
import { serverFileManager } from '$lib/files.server'

export const GET: RequestHandler = async ({ params }) => {
return await serverFileManager.streamFile(params.fileId)
}

streamFile returns a Response with headers for Content-Type, Content-Length, Content-Disposition (inline), and Cache-Control (private, 1 hour).

Public Files

For files that don't need auth, make the bucket public and serve directly from S3.

Make a Bucket Public

// On creation
await serverFileManager.createBucket('public-bucket', { public: true })

// Or after the fact
await serverFileManager.makeBucketPublic('public-bucket')

This applies an S3 bucket policy allowing public GetObject access.

Client File Manager

Generate public URLs on the client:

// lib/files.client.ts
import { env } from '$env/dynamic/public'
import { ClientFileManager } from '@repo/storage'

export const clientFileManager = new ClientFileManager({
s3: {
endpoint: env.PUBLIC_S3_ENDPOINT,
},
})
const url = clientFileManager.getClientFileUrl({
key: file.key,
bucket: file.bucket,
})
// => "https://s3.example.com/public-bucket/abc-123.png"

Returns undefined if the input is undefined.