Configuration
Learn how to configure Torrin for optimal performance in your application. This guide covers chunk size, concurrency, retries, and more.
Client Configuration
Creating the Client
import { createTorrinClient } from '@torrin-kit/client';
const torrin = createTorrinClient({
endpoint: 'http://localhost:3000/api/uploads',
defaultChunkSize: 5 * 1024 * 1024, // 5MB chunks
maxConcurrency: 3, // Upload 3 chunks at once
retryAttempts: 5, // Retry failed chunks 5 times
retryDelay: 2000, // 2 second initial delay
headers: async () => ({
Authorization: `Bearer ${await getToken()}`,
}),
});Chunk Size
The chunk size determines how large each piece of the file will be. Smaller chunks mean more network requests but better progress granularity and resume capability.
Recommendations:
- Small files (<10MB): 256KB - 1MB
- Medium files (10MB - 1GB): 1MB - 5MB
- Large files (>1GB): 5MB - 20MB
// Global default
const torrin = createTorrinClient({
endpoint: '/api/uploads',
defaultChunkSize: 5 * 1024 * 1024, // 5MB
});
// Per-upload override
const upload = torrin.createUpload({
file,
chunkSize: 10 * 1024 * 1024, // Use 10MB for this file
});Concurrency
Control how many chunks upload simultaneously. Higher concurrency = faster uploads but more memory/bandwidth usage.
const torrin = createTorrinClient({
endpoint: '/api/uploads',
maxConcurrency: 5, // Upload 5 chunks in parallel
});Recommendations:
- Slow connections: 1-2
- Normal connections: 3-5
- Fast connections: 5-10
Retry Configuration
Configure how the client handles failed chunk uploads:
const torrin = createTorrinClient({
endpoint: '/api/uploads',
retryAttempts: 5, // Retry each failed chunk up to 5 times
retryDelay: 1000, // Start with 1 second delay, exponential backoff
});The delay uses exponential backoff:
- Attempt 1: 1000ms
- Attempt 2: 2000ms
- Attempt 3: 4000ms
- Attempt 4: 8000ms
- Attempt 5: 16000ms
Authentication
Add custom headers for authentication:
// Static headers
const torrin = createTorrinClient({
endpoint: '/api/uploads',
headers: () => ({
Authorization: 'Bearer static-token',
'X-Custom-Header': 'value',
}),
});
// Dynamic headers (async)
const torrin = createTorrinClient({
endpoint: '/api/uploads',
headers: async () => {
const token = await getAccessToken();
return {
Authorization: `Bearer ${token}`,
};
},
});Headers are fetched for each request, so tokens are always fresh.
Server Configuration
Express.js
import { createTorrinExpressRouter } from '@torrin-kit/server-express';
import { createLocalStorageDriver } from '@torrin-kit/storage-local';
import { createInMemoryStore } from '@torrin-kit/server';
const torrinRouter = createTorrinExpressRouter({
// Required
storage: createLocalStorageDriver({ baseDir: './uploads' }),
store: createInMemoryStore(),
// Optional
defaultChunkSize: 1024 * 1024, // 1MB (clients can override)
maxChunkSize: 100 * 1024 * 1024, // 100MB hard limit
uploadTtlMs: 24 * 60 * 60 * 1000, // 24 hours
// Lifecycle hooks
onBeforeInit: async (req, res) => {
// Authenticate user
if (!req.headers.authorization) {
throw new Error('Unauthorized');
}
},
onBeforeChunk: async (req, res) => {
// Rate limiting, logging, etc.
},
onBeforeComplete: async (req, res) => {
// Virus scanning, validation, etc.
},
});NestJS
import { Module } from '@nestjs/common';
import { TorrinModule } from '@torrin-kit/server-nestjs';
import { createLocalStorageDriver } from '@torrin-kit/storage-local';
import { createInMemoryStore } from '@torrin-kit/server';
@Module({
imports: [
TorrinModule.forRoot({
storage: createLocalStorageDriver({ baseDir: './uploads' }),
store: createInMemoryStore(),
defaultChunkSize: 1024 * 1024,
maxChunkSize: 100 * 1024 * 1024,
uploadTtlMs: 24 * 60 * 60 * 1000,
}),
],
})
export class AppModule {}TTL (Time To Live)
Configure how long upload sessions remain valid:
createTorrinExpressRouter({
storage,
store,
uploadTtlMs: 24 * 60 * 60 * 1000, // 24 hours
});After this time, incomplete uploads are eligible for cleanup. See TTL & Cleanup for more details.
Chunk Size Limits
createTorrinExpressRouter({
storage,
store,
defaultChunkSize: 1024 * 1024, // Suggested chunk size (1MB)
maxChunkSize: 50 * 1024 * 1024, // Maximum allowed (50MB)
});If a client requests a chunk size larger than maxChunkSize, the server will reject the upload initialization.
Per-Upload Configuration
File Metadata
Attach custom metadata to uploads:
const upload = torrin.createUpload({
file,
metadata: {
userId: '12345',
projectId: 'abc',
tags: ['video', 'tutorial'],
description: 'Q1 2024 training video',
},
});Metadata is sent to the server during initialization and can be accessed in hooks:
onBeforeInit: async (req, res) => {
const { metadata } = req.body;
console.log('User:', metadata.userId);
// Validate metadata
if (!metadata.projectId) {
throw new Error('Project ID required');
}
},Custom Chunk Size
Override the default chunk size for specific files:
const upload = torrin.createUpload({
file,
chunkSize: 10 * 1024 * 1024, // 10MB for this upload
});Environment-Specific Configs
Development
const torrin = createTorrinClient({
endpoint: 'http://localhost:3000/api/uploads',
defaultChunkSize: 1024 * 1024, // 1MB for faster testing
maxConcurrency: 2,
retryAttempts: 3,
});Production
const torrin = createTorrinClient({
endpoint: 'https://api.example.com/uploads',
defaultChunkSize: 5 * 1024 * 1024, // 5MB for efficiency
maxConcurrency: 5,
retryAttempts: 5,
headers: async () => ({
Authorization: `Bearer ${await getToken()}`,
}),
});Best Practices
- Match chunk size to network speed: Faster networks can handle larger chunks
- Limit concurrency on mobile: Mobile networks benefit from lower concurrency (2-3)
- Always use TTL: Prevent abandoned uploads from consuming storage
- Add authentication: Validate users in
onBeforeInithook - Consider file type: Videos can use larger chunks, images/docs use smaller
- Monitor and adjust: Track upload success rates and adjust configuration
Next Steps
- Resume & Persistence - Enable automatic resume
- Error Handling - Handle failures gracefully
- TTL & Cleanup - Manage abandoned uploads
- Storage Drivers - Configure storage backends