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 ​