Skip to content

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

typescript
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
typescript
// 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.

typescript
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:

typescript
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:

typescript
// 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

typescript
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

typescript
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:

typescript
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

typescript
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:

typescript
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:

typescript
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:

typescript
const upload = torrin.createUpload({
  file,
  chunkSize: 10 * 1024 * 1024, // 10MB for this upload
});

Environment-Specific Configs

Development

typescript
const torrin = createTorrinClient({
  endpoint: 'http://localhost:3000/api/uploads',
  defaultChunkSize: 1024 * 1024, // 1MB for faster testing
  maxConcurrency: 2,
  retryAttempts: 3,
});

Production

typescript
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

  1. Match chunk size to network speed: Faster networks can handle larger chunks
  2. Limit concurrency on mobile: Mobile networks benefit from lower concurrency (2-3)
  3. Always use TTL: Prevent abandoned uploads from consuming storage
  4. Add authentication: Validate users in onBeforeInit hook
  5. Consider file type: Videos can use larger chunks, images/docs use smaller
  6. Monitor and adjust: Track upload success rates and adjust configuration

Next Steps