nuxt-file-save

A nuxt plugin for file uploading to local disk
1,328 3
Install
npm install nuxt-file-save
Latest Version:1.2.6
Vue:3
License:MIT
Last Updated:Sep 9, 2026
Links: GitHub  ·  npm
Maintainer: wzo

Nuxt File Save

npm version npm downloads License Nuxt

A nuxt plugin for file uploading to local disk

Features

  • ⛰  Configurable, support for multi-file upload
  • 🚠  The type and size of the file are checked on the back end
  • 🌲  Save to the local disk

Quick Setup

Install the module to your Nuxt application with one command:

npx nuxi module add nuxt-file-save

Or add it manually to your nuxt.config.ts:

# Using pnpm
pnpm add -D nuxt-file-save

# Using yarn
yarn add --dev nuxt-file-save

# Using npm
npm install --save-dev nuxt-file-save
export default defineNuxtConfig({
    modules: ['nuxt-file-save'],
    fileSave: {
        // The location where the file is saved to disk, public by default, in the public folder at the root of the current project
        mount:'public',
        // Verify the configuration item associated with the upload file, overwriting it in the 'useFileVerify' method
        // options?: BlobUploadOptions
    }
})

That's it! You can now use Nuxt File Save in your Nuxt app ✨

Usage

Handling Files in the frontend

Just send the formData format data to the backend

<template>
    <input type="file" multiple @change="handleFileChange" />
</template>

<script setup>
const handleFileChange = (e: any) => {
    const files = e.target.files[0]
    if (!files) return

    const formData = new FormData()
    formData.append('files', files.value)

    // You can also verify before uploading the file
    // try {
    //     await useFileVerify(formData, {
    //         ensure: {
    //             maxSize: '100MB',
    //             types: ['audio', 'image', 'video', 'pdf', 'zip'],
    //         },
    //     })
    // } catch (error) {
    //     alert(error)
    //     return
    // }
    const res = await $fetch<{code: number, data: string, msg: string}>('/api/upload', {
        method: 'POST',
        body: formData,
    })
    console.log(res)
    if(res.code !== 200){ // fail
        return alert(res.msg)
    }

}
</script>

Handling files in the backend

On the server side, the useFileVerify method is used to verify the file, and the useFileSave method is used to save it

// server/api/upload.ts

export default defineEventHandler(async (event) => {
    try {
        const form = await readFormData(event)

        // multiple
        // const files = await useFileVerify(form, {
        //     multiple: 3, // Max 3 files at a time for now
        //     ensure: {
        //         maxSize: '50MB', // Max 50 MB each file
        //         types: ['audio', 'csv', 'image', 'video', 'pdf', 'text'], // Only allow these file types
        //     },
        // });

        // for (const file of files) {
        //     await useFileSave(file);
        // }

        // single
        const [file] = await useFileVerify(form, {
            formKey: 'files', // The key of the form data
            multiple: false, // Only allow one file at a time
            ensure: {
                maxSize: '256MB',
                types: ['audio', 'csv', 'image', 'video', 'pdf', 'text', 'zip', 'exe'],
            },
            lang: 'en', // Language for error messages
        })

        const date = new Date()
        // Generate folders based on time
        const dateDir = date.toLocaleDateString('zh-cn') // 2023/01/02
        // const dateDir = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
        const randomStr = Math.random().toString(36).substring(2, 6 + 2) // Random String 6 bits
        const fileDir = `/upload/${dateDir}`
        const url = await useFileSave(file, `${Date.now()}-${randomStr}`, fileDir)
        if (!url) return { code: 500, msg: 'error' }
        return { code: 200, msg: 'success', data: url }
    } catch (error: any) {    // eslint-disable-line
        return { code: error.statusCode, msg: error.message }
    }
})

If you don't want to check the file, just save the file

const form = await readFormData(event)
const [file] = form.getAll('files') as File[]
if (file) {
    const url = await useFileSave(file)
}

Method

useFileVerify(form: FormData, options?: BlobUploadOptions)

A method of receiving and validating files

  • form: FormData object
  • options: BlobUploadOptions object

Options:

  • formKey: The key of the form data, default is files
  • multiple: Whether to allow multiple files, The type is number | boolean, default is true
  • ensure: The file validation rules, File size and file type
  • lang: The language for error messages, default is en

Returns:

  • An array of File objects, If validation fails and an error message is thrown, you can use try.catch

Example:

// multiple
const files = await useFileVerify(form, {
    multiple: 3, // Max 3 files at a time for now
    ensure: {
        maxSize: '50MB', // Max 50 MB each file
        types: ['audio', 'csv', 'image', 'video', 'pdf', 'text'], // Only allow these file types
    },
});

try{
    // single
    const [file] = await useFileVerify(form, {
        formKey: 'files', // The key of the form data
        multiple: false, // Only allow one file at a time
        ensure: {
            maxSize: '256MB',
            types: ['audio', 'csv', 'image', 'video', 'pdf', 'text', 'zip', 'exe'],
        },
        lang: 'en', // Language for error messages
    })
}catch(e){
    // error info
}

useFileSave(file: File, fileName = file.name, fileDir?: string)

A method of uploading files.

  • file is the file object data.
  • fileName is the fileName, which defaults to the original fileName, or you can use a string with no suffix.
  • fileDir is the directory where the file is stored.

Returns:

  • The file url, Also using try.catch gets the error message

Example:

const url = await useFileSave(file, `${Date.now()}`, 'upload')

Type Declarations

Show Type Declarations
export type FileSizeUnit = 'B' | 'KB' | 'MB' | 'GB' | 'TB'
export type BlobSize = `${number}${FileSizeUnit}`
export type BlobType =
    | 'image'
    | 'video'
    | 'audio'
    | 'pdf'
    | 'csv'
    | 'text'
    | 'blob'
    | (string & Record<never, never>)
export type MessageLangType = 'en'|'zh'
export interface BlobUploadOptions {
    /**
     * The key to get the file/files from the request form.
     * @default 'files'
     */
    formKey?: string
    /**
     * Whether to allow multiple files to be uploaded.
     * @default true
     */
    multiple?: boolean | number
    /**
     * Options used for the ensure() method.
     */
    ensure?: BlobEnsureOptions
    /**
     * The language in which the text message corresponds
     * @default 'en'
     */
    lang?: MessageLangType
}

export interface BlobEnsureOptions {
    /**
     * The maximum size of the blob (e.g. '1MB')
     */
    maxSize?: BlobSize
    /**
     * The allowed types of the blob (e.g. ['image/png', 'application/json', 'video'])
     */
    types?: BlobType[]
}

Error message code

code message
1000 Received invalid file
1001 Invalid file type. Only allowed: {{types}}
1002 File too heavy. Max size is: {{maxSize}}
1003 No files received
1004 Multiple files are not allowed
1005 Number of files exceeded, Maximum allowed: {{multiple}}
1006 Invalid file size format: {{blobSize}}
1007 Invalid file size unit: {{sizeUnit}}
1008 Error uploading file

And that's it! Now you can use it happily in your project ✨

Cautions (production environment related)

(node:24872) ExperimentalWarning: buffer.File is an experimental feature and might change at any time

  • The message you are receiving isn't an issue, it's a warning emitted from the use of an experimental feature.

This library saves files to the public folder, so we can access them directly in the project.for example:

<img src="https://raw.githubusercontent.com/nowo/nuxt-file-save/HEAD/upload/1678438436123.png" alt="image" />

But in a production environment, when we use nuxt build to build a project, the /public file will be copied to .output/public(which will result in an increase in disk space), but in reality, the file will only be saved to /public.

For production environment problem, I suggest using nginx to configure proxies to solve them

Recommended: store uploads outside public

Rather than relying on the public folder (which nuxt build copies into .output/public), point mount to a dedicated directory on the server in production and let nginx serve it directly. The uploaded files then live entirely outside the build output, so the copy issue above no longer applies and re-deploying never overwrites them:

// nuxt.config.ts
export default defineNuxtConfig({
    modules: ['nuxt-file-save'],
    fileSave: {
        // 'public' in dev; an absolute, nginx-served directory in production
        mount: process.env.NODE_ENV === 'production' ? '/home/project/uploads' : 'public',
    },
})

Then point nginx at that directory — just set the alias in the config below to your mount path (e.g. alias /home/project/uploads/upload;).

Run the project using PM2

// ecosystem.config.js  
// or 
// ecosystem.config.cjs 
module.exports = {
    apps: [
        {
            name: 'nuxt-web', // Sets the name of the PM2 process
            port: '8000', // The port on which the project runs
            exec_mode: 'cluster',
            instances: 'max',
            script: './.output/server/index.mjs',
            env: {
            },
        },
    ],
}
  

Run the project, if filename is ecosystem.config.js, ecosystem.config.js can be omitted

pm2 start ecosystem.config.js 
# or 
pm2 start ecosystem.config.cjs

Nginx configuration

# nuxt-web.conf
server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    # Set variables, project root directory
    set $base_path /home/project/nuxt-web;

    location / {
        root  $base_path;
        proxy_pass   http://127.0.0.1:8000;
    }
    
    #############################################################
    # Change the directory accessed by `/upload`, Example of `useFileSave(file, '', '/upload')` with the third parameter '/upload'
    location ^~/upload {
        alias $base_path/public/upload; # Set access to file directory
        autoindex on;
        autoindex_exact_size off; # Display file size in MB, GB format instead of KB
        autoindex_localtime on; # The file time is the time of the server
        if ($request_filename ~* ^.*?\.(txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx|png|jpg|gif|webp)$){
            add_header Content-Disposition attachment;
            add_header  Content-Type application/octet-stream;
        } # These files with suffixes can be downloaded
    }
    #############################################################
}

At this point, the access path of /upload has been changed, and files uploaded in the production environment can still be accessed normally. The .output/public/upload folder can also be deleted or not

Contribution

Run into a problem? Open a new issue. I'll try my best to include all the features requested if it is fitting to the scope of the project.

Want to add some feature? PRs are welcome!

  • Clone this repository
  • install the dependencies
  • prepare the project
  • run dev server
git clone https://github.com/nowo/nuxt-file-save && cd nuxt-file-save
pnpm i
pnpm run dev:prepare
pnpm run dev

License

MIT - Copyright (c) 2024 nowo

Related Packages

file-uploader-vue-component

A vuejs component of file uploader.

3,739 12
@privyid/nuxt-csrf

Module CSRF for NUXT

26,088 9
mixpanel-nuxt

Mixpanel module for Nuxt

19,992 7
nuxt-radash

radash for Nuxt

10,601 20
gsap-nuxt-module

GSAP integration for Nuxt.

8,932 37

Version History

Version Released Vue License
1.2.6 ^3.0 MIT
1.2.5 ^3.0 MIT
1.2.4 ^3.0 MIT
1.2.3 ^3.0 MIT
1.2.2 ^3.0 MIT
Pre-releases (1)
Version Released Vue License
1.1.1-0 ^3.0 MIT