npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-file-downloader

v1.1.0

Published

Universal file download library for Next.js, React, and browser with automatic CORS fallback, proxy streaming route, and progress tracking.

Readme

next-file-downloader 🚀

Package tout-en-un pour télécharger tout type de fichier en Next.js, React et Node.js sans se casser la tête avec les CORS, les URLs cloud/S3 ou la gestion des streams.

npm version License: MIT TypeScript


🎯 Pourquoi cette librairie ?

Dans les projets Next.js ou React, un backend envoie très souvent une URL vers un stockage cloud (ex: AWS S3, Cloudflare R2, Google Cloud Storage, Supabase, Scaleway) :

{
  "resumeUrl": "https://my-bucket.s3.eu-west-1.amazonaws.com/candidates/cv/sample-candidate-resume.pdf"
}

Quand vous tentez de le télécharger depuis le navigateur :

  1. <a href={url} download> ne fonctionne pas pour les URLs cross-origin : le navigateur ouvre le PDF au lieu de déclencher le téléchargement.
  2. fetch(url) -> blob() échoue avec une erreur CORS si le bucket S3 n'a pas configuré les headers spécifiques.
  3. Écrire à chaque fois une API route manuellement dans Next.js (gérer les headers Content-Disposition, les streams et le typage) devient vite répétitif et fatiguant.

next-file-downloader résout tout cela :

  • ✅ Route API Next.js prête en 1 ligne (createDownloadRoute) avec streaming natif et protection SSRF.
  • ✅ Fonction client universelle (downloadFile) avec détection automatique et repli vers le proxy en cas de CORS.
  • ✅ Hook React complet (useFileDownload) avec état de chargement, progression en pourcentage (0-100%) et annulation (abort).
  • ✅ Déduction intelligente du nom de fichier (depuis le header HTTP Content-Disposition, l'URL ou un nom personnalisé).
  • ✅ Zéro dépendance lourde, TypeScript first, compatible Next.js App Router & Pages Router.

📦 Installation

npm install next-file-downloader
# ou
yarn add next-file-downloader
# ou
pnpm add next-file-downloader

🚀 Utilisation rapide

1. En une ligne de code (Côté Client)

import { downloadFile } from 'next-file-downloader';

// Télécharge et extrait automatiquement le nom depuis l'URL cloud
await downloadFile('https://my-bucket.s3.eu-west-1.amazonaws.com/candidates/cv/sample-candidate-resume.pdf');

// Ou avec un nom personnalisé :
await downloadFile(resumeUrl, {
  filename: 'CV_Candidat.pdf',
});

2. Avec la Route Proxy Next.js (Recommandé pour Cloud & S3)

Si votre bucket n'a pas activé les CORS ou si vous voulez garantir le téléchargement sur tous les navigateurs sans jamais être bloqué :

👉 Créez votre route Next.js App Router :

Créez le fichier src/app/api/download/route.ts (ou app/api/download/route.ts) :

// src/app/api/download/route.ts
import { createDownloadRoute } from 'next-file-downloader/server';

// Par défaut, accepte TOUTES les URLs venant de vos backends (app..., api..., cloud, etc.)
export const { GET, POST } = createDownloadRoute({
  // Optionnel : forwarde automatiquement les tokens d'authentification (Bearer, etc.)
  forwardHeaders: true,

  // Optionnel : si vous souhaitez restreindre à certains domaines spécifiques
  // allowedDomains: ['*.amazonaws.com', 'app.monsite.com'],
});

👉 Appelez-le simplement depuis votre composant :

import { downloadFile } from 'next-file-downloader';

await downloadFile(resumeUrl, {
  filename: 'Candidature_CV.pdf',
  proxyUrl: '/api/download', // Utilise le proxy ou s'y replie automatiquement en cas de CORS !
});

3. Avec le Hook React (useFileDownload)

Idéal pour afficher un bouton avec spinner et pourcentage de téléchargement :

'use client';

import { useFileDownload } from 'next-file-downloader/react';

export function DownloadCvButton({ resumeUrl }: { resumeUrl: string }) {
  const { download, isDownloading, progress, error } = useFileDownload({
    proxyUrl: '/api/download',
  });

  return (
    <div>
      <button
        disabled={isDownloading}
        onClick={() =>
          download(resumeUrl, {
            filename: 'CV_Collaborateur.pdf',
          })
        }
        className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50"
      >
        {isDownloading
          ? `Téléchargement ${progress?.percent ? `(${progress.percent}%)` : '...'}`
          : 'Télécharger le CV'}
      </button>

      {error && <p className="text-red-500 text-sm mt-1">Erreur: {error.message}</p>}
    </div>
  );
}

🛠️ Modes de téléchargement

L'option mode vous permet de contrôler la stratégie :

| Mode | Description | | :--- | :--- | | 'auto' (défaut) | Tente le téléchargement direct. Si une erreur CORS ou réseau survient et qu'un proxyUrl est fourni, bascule automatiquement sur le proxy. | | 'proxy' | Force le passage par l'API Route Next.js (proxyUrl). Idéal pour les buckets privés ou sans CORS. | | 'direct' | Utilise un tag DOM <a href="..." download> classique. | | 'blob' | Télécharge en mémoire sous forme de Blob et déclenche la sauvegarde. |

await downloadFile(url, {
  mode: 'proxy',
  proxyUrl: '/api/download',
  filename: 'Rapport.xlsx',
});

📑 Utilitaires supplémentaires

import {
  downloadBlob,
  downloadBase64,
  getFilenameFromUrl,
  sanitizeFilename,
} from 'next-file-downloader';

// 1. Extraire le nom de fichier d'une URL :
const name = getFilenameFromUrl('https://my-bucket.s3.amazonaws.com/docs/mon-fichier.pdf?auth=123');
// -> "mon-fichier.pdf"

// 2. Nettoyer un nom de fichier pour éviter les caractères invalides :
const safe = sanitizeFilename('CV / Candidat : 2026?.pdf');
// -> "CV _ Candidat _ 2026_.pdf"

// 3. Télécharger un Blob déjà existant :
downloadBlob(myBlob, 'export.csv');

// 5. Forcer le téléchargement direct sur S3/Cloud sans route API :
import { appendS3DownloadParam } from 'next-file-downloader';

const directUrl = appendS3DownloadParam('https://my-bucket.s3.amazonaws.com/cv.pdf', 'Mon_CV.pdf');
// -> 'https://my-bucket.s3.amazonaws.com/cv.pdf?response-content-disposition=attachment%3B+filename%3D%22Mon_CV.pdf%22'

💡 Comment se passer à 100% de l'API Route ?

Si vous ne voulez aucune route API serveur et faire 100% des téléchargements directement dans le navigateur client, vous avez 2 solutions :

Solution 1 : Activer les CORS sur votre Cloud Storage (Recommandé - 2 minutes)

Par défaut, les buckets AWS S3, Scaleway Object Storage, Cloudflare R2 ou Supabase bloquent les requêtes venant d'un navigateur pour des raisons de sécurité.

Il vous suffit de coller cette règle CORS dans la console de votre fournisseur (AWS / Scaleway / Cloudflare R2 / Supabase) :

[
  {
    "AllowedOrigins": ["*"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["Content-Disposition", "Content-Length"],
    "MaxAgeSeconds": 3600
  }
]

👉 Résultat : Dès que cette règle est activée sur votre bucket, vous n'avez plus besoin d'aucune API route ! Le navigateur télécharge directement :

await downloadFile('https://mon-bucket.s3.../fichier.pdf', {
  filename: 'Rapport.pdf',
});

Solution 2 : Utiliser le paramètre S3 response-content-disposition

AWS S3, Scaleway, Google Cloud et Cloudflare R2 supportent un paramètre d'URL natif : ?response-content-disposition=attachment; filename="mon-fichier.pdf"

Quand ce paramètre est présent dans l'URL, le serveur Cloud Storage renvoie automatiquement l'ordre au navigateur de télécharger le fichier (au lieu de l'afficher dans un onglet), sans aucun problème de CORS et sans aucune API route !

Côté client avec next-file-downloader :

// Téléchargement direct avec injection automatique du paramètre S3 :
await downloadFile(s3Url, {
  filename: 'Mon_CV.pdf',
  mode: 'direct', // ou fallbackToDirect: true
});

Ou côté backend si votre backend génère des URLs pré-signées :

// Exemple Backend (AWS SDK / Scaleway) :
const url = await getSignedUrl(s3Client, new GetObjectCommand({
  Bucket: 'mon-bucket',
  Key: 'cv.pdf',
  ResponseContentDisposition: 'attachment; filename="Mon_CV.pdf"',
}));

Le navigateur téléchargera alors directement le fichier sans avoir besoin d'un proxy serveur !


🔒 Sécurité du Serveur (next-file-downloader/server)

La fonction createDownloadRoute intègre de base :

  • Protection anti-SSRF : blocage automatique des adresses locales (localhost, 127.0.0.1, adresses IP privées 10.x, 192.168.x, métadonnées cloud 169.254.169.254).
  • Support des Wildcards : ex. allowedDomains: ['*.amazonaws.com', '*.my-storage.com'].
  • Streaming sans mise en cache RAM : les fichiers volumineux ne saturent pas la mémoire du serveur Node / Next.js.
  • Support complet UTF-8 : les noms de fichiers avec accents et espaces sont préservés grâce à la norme RFC 5987 (filename*=UTF-8''...).

Exemple personnalisé côté serveur :

import { handleDownloadRequest } from 'next-file-downloader/server';

export async function GET(req: Request) {
  // Vos vérifications d'authentification éventuelles :
  // const session = await auth();
  // if (!session) return new Response('Unauthorized', { status: 401 });

  return handleDownloadRequest(req, {
    allowedDomains: ['*.amazonaws.com'],
    maxSizeBytes: 50 * 1024 * 1024, // Limite à 50 Mo
  });
}

📄 Licence

MIT