> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filerouter.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# File Size Limits and Large Document Uploads with FileRouter

> Hosted FileRouter accepts uploads up to 100 MB. Learn how to handle larger files with BYOK direct mode, URL inputs, and the CLI's --local flag.

Every document you submit to FileRouter flows through one of two paths: the hosted service (managed credentials, durable jobs, result storage) or a direct BYOK call through the `FileRouter` SDK class (your own provider keys, provider's own limits apply). Understanding which path you're on determines which size limits apply to your uploads.

## Hosted service: 100 MB upload ceiling

The hosted FileRouter API accepts files up to **100 MB** per request. When you upload a binary file, it streams securely into storage — FileRouter never buffers the entire file during ingress.

```ts title="Upload a file to the hosted service" theme={null}
import { FileRouterClient } from '@file_router/sdk'

const client = new FileRouterClient({ apiKey: process.env.FILEROUTER_API_KEY })

// Files up to 100 MB stream directly into storage
const result = await client.parse(largeFile, {
  outputs: ['markdown'],
  provider: 'llamaparse',
})
```

<Info>
  In production, FileRouter gives each provider a short-lived, scoped source URL to fetch the document securely. The document is processed directly by the provider and is never re-buffered by the service. After the provider completes, the uploaded source is deleted.
</Info>

## Binary uploads use request headers

When you upload a binary file (rather than a JSON body with a URL), the SDK sets the job parameters as HTTP headers instead of a JSON body. The file bytes become the raw request body. The SDK handles this automatically — you don't need to construct these headers yourself.

| Header                          | Purpose                                              |
| ------------------------------- | ---------------------------------------------------- |
| `X-FileRouter-Operation`        | `parse` or `compare`                                 |
| `X-FileRouter-Outputs`          | Comma-separated output list (e.g. `markdown,tables`) |
| `X-FileRouter-Filename`         | URL-encoded original filename                        |
| `X-FileRouter-Provider`         | Provider ID for parse operations                     |
| `X-FileRouter-Providers`        | Comma-separated provider IDs for compare operations  |
| `X-FileRouter-Pages`            | Comma-separated one-based page numbers               |
| `X-FileRouter-Include-Raw`      | `true` or `false`                                    |
| `X-FileRouter-Provider-Options` | URL-encoded JSON of the `providerOptions` object     |
| `Content-Type`                  | The file's MIME type                                 |

## URL inputs

Instead of uploading a binary file, you can pass a publicly accessible HTTP or HTTPS URL. FileRouter (or the downstream provider) fetches the document directly from that URL:

```ts title="Parse a document by URL" theme={null}
const result = await client.parse('https://example.com/annual-report.pdf', {
  outputs: ['markdown', 'tables'],
  provider: 'mistral-ocr',
})
```

URL inputs send a JSON body rather than a binary stream, so the 100 MB hosted upload ceiling does not apply to the URL itself. The provider fetches the document directly, subject to that provider's own download limits and timeout policies.

<Warning>
  The URL must be publicly accessible over HTTP or HTTPS. FileRouter cannot fetch documents from `localhost`, private networks, or URLs requiring authentication headers. Use a public development tunnel when testing with local files during hosted development.
</Warning>

## Files above 100 MB

For files larger than 100 MB, you have two options:

<Tabs>
  <Tab title="BYOK direct mode (SDK)">
    Use the `FileRouter` class directly with a provider adapter. This bypasses the hosted service entirely — your document goes straight to the provider using your own API key. The 100 MB ceiling doesn't apply; each provider's own file-size limits govern the request.

    ```ts title="BYOK direct mode — bypasses the hosted ceiling" theme={null}
    import { FileRouter } from '@file_router/sdk'
    import { llamaparse } from '@file_router/sdk/llamaparse'

    const router = new FileRouter({
      providers: {
        llamaparse: llamaparse({
          apiKey: process.env.LLAMA_CLOUD_API_KEY,
        }),
      },
    })

    // No hosted ceiling — LlamaParse's own limits apply
    const result = await router.parse(veryLargeFile, {
      outputs: ['markdown'],
      provider: 'llamaparse',
    })
    ```

    <Tip>
      Provider responses — especially those with extracted images or raw JSON output — can be large. Pass `includeRaw: true` only when you genuinely need the full provider response. Omitting it keeps memory usage and response sizes lower.
    </Tip>
  </Tab>

  <Tab title="CLI with --local flag">
    The CLI's `--local` flag routes the job through BYOK direct mode. Set the provider's standard environment variable and add `--local` to your command:

    ```bash title="Parse a large file locally with BYOK" theme={null}
    LLAMA_CLOUD_API_KEY=your-key npx @file_router/cli parse large-document.pdf --local
    ```

    ```bash title="Use Mistral OCR locally" theme={null}
    MISTRAL_API_KEY=your-key npx @file_router/cli parse large-document.pdf --local --provider mistral-ocr
    ```

    The `--local` flag bypasses the hosted service and the 100 MB ceiling. The file is submitted directly to the provider from your machine.
  </Tab>
</Tabs>

## Provider native file limits

In BYOK direct mode, each provider enforces its own size and format limits independently of FileRouter. Consult each provider's documentation for their current ceilings. FileRouter normalizes errors from providers into `FileRouterError` with a `ParseFailed` code, so your error handling doesn't need to be provider-specific.

## Result retention

<Accordion title="How long are results available?">
  Hosted job results are available for **7 days** after the job completes. After 7 days, requesting the job returns **HTTP 410 Gone**. Job records themselves are removed after 30 days.

  If you need results beyond the 7-day window, retrieve and store the result data in your own storage before it expires.

  ```ts title="Handle expired results gracefully" theme={null}
  try {
    const result = await client.parse(file, { outputs: ['markdown'] })
    // Store result.outputs.markdown in your own storage
  } catch (error) {
    if (error.status === 410) {
      // Result has expired — resubmit the job
    }
  }
  ```
</Accordion>

## Summary

| Scenario               | Ceiling               | How to handle                                      |
| ---------------------- | --------------------- | -------------------------------------------------- |
| Hosted binary upload   | 100 MB                | Use BYOK direct mode or URL input for larger files |
| Hosted URL input       | No hosted ceiling     | Provider fetches directly; provider limits apply   |
| BYOK direct mode (SDK) | Provider's own limits | Use `FileRouter` class + provider adapter          |
| CLI `--local`          | Provider's own limits | Add `--local` flag; set provider env var           |
| Result availability    | 7 days                | Fetch and store results before expiry              |
