Stable, fast, robust, and well-maintained Meteor.js package for files management using MongoDB Collection API. Call .insertAsync() method to initiate a file upload and to insert new record into MongoDB collection after upload is complete. Calling .removeAsync() method would erase stored file and record from MongoDB Collection. And so on, no need to learn new APIs. Hackable via hooks and events. Supports uploads to AWS:S3, GridFS, Google Storage, DropBox, and other 3rd party storage.
- π Documentation - Docs, API, Demos, Examples
- β¨ Key features
- π API Documentation
- β‘οΈ Quick start:
- π€ FAQ
- π Awards
- πββοΈ Get Help
- ποΈ Demo applications
- π¦ Related Packages
- π Support this project
- π¨βπ» Contribute to this project
- π Supporters
- Compatible with all front-end frameworks from Blaze to React
- Upload via
HTTPandDDPtransports, read about difference - Sustainable and "resumable" uploads will auto-resume when connection interrupted or server rebooted
- Upload files through computing cloud without persistent File System, like Heroku ("resumable" uploads are not supported on Heroku and alike)
- Use GridFS, AWS S3, Google Storage or DropBox and other (3rd-party storage)
- APIs for checking file mime-type, size, extension, an other file's properties before upload using
onBeforeUploadhook - APIs for resizing images, subversions management, and other post-processing tasks using
onAfterUploadandonAfterRemovehooks
Install ostrio:files from Atmosphere
meteor add ostrio:filesImport in isomorphic location (e.g. on server and client)
import { FilesCollection } from 'meteor/ostrio:files';For detailed docs, examples, and API β read documentation section.
Main methods:
FilesCollectionConstructor [Anywhere] - Initialize FilesCollectioninsertAsync()[Client] - Upload a file to server, returnsFileUploadinstancelink()[Anywhere] - Generate downloadable linkfind()[Anywhere] - Find all files matching selector, returnsFilesCursorinstancefindOneAsync()[Anywhere] - Find a single file record matching selector, returnsFileCursorinstanceremoveAsync()[Anywhere] - Asynchronously remove files from FilesCollection and "unlink" (e.g. remove) from ServeraddFile()[Server] - Add local file to FilesCollection from FSloadAsync()[Server] - Write file to FS and FilesCollection from remote URLwriteAsync()[Server] - WriteBufferto FS and FilesCollection
[Anywhere]. Initiate file's collection in the similar way to Mongo.Collection with optional settings related to file-uploads. Read full docs for FilesCollection Constructor in the API documentation.
import { FilesCollection } from 'meteor/ostrio:files';
new FilesCollection(FilesCollectionConfig);Pass additional options to control upload-flow
// shared: /imports/lib/collections/images.collection.js
import { Meteor } from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';
const imagesCollection = new FilesCollection({
collectionName: 'images',
allowClientCode: false, // Disallow remove files from Client
onBeforeUpload(file) {
// Allow upload files under 10MB, and only in png/jpg/jpeg formats
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.extension)) {
return true;
}
return 'Please upload image, with size equal or less than 10MB';
}
});
if (Meteor.isClient) {
// SUBSCRIBE TO ALL UPLOADED FILES ON THE CLIENT
Meteor.subscribe('files.images.all');
}
if (Meteor.isServer) {
// PUBLISH ALL UPLOADED FILES ON THE SERVER
Meteor.publish('files.images.all', function () {
return imagesCollection.collection.find();
});
}import { FilesCollection } from 'meteor/ostrio:files';
const files = new FilesCollection(FilesCollectionConfig);
files.insertAsync(config: InsertOptions, autoStart?: boolean): Promise<FileUpload | UploadInstance>;Read full docs for insertAsync() method
Upload form (template):
<template name="uploadForm">
{{#with currentUpload}}
Uploading <b>{{file.name}}</b>:
<span id="progress">{{progress.get}}%</span>
{{else}}
<input id="fileInput" type="file" />
{{/with}}
</template>Shared code:
import { FilesCollection } from 'meteor/ostrio:files';
const imagesCollection = new FilesCollection({collectionName: 'images'});
export default imagesCollection; // import in other filesClient's code:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
Template.uploadForm.onCreated(function () {
this.currentUpload = new ReactiveVar(false);
});
Template.uploadForm.helpers({
currentUpload() {
return Template.instance().currentUpload.get();
}
});
Template.uploadForm.events({
async 'change #fileInput'(e, template) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// multiple files were selected
const upload = await imagesCollection.insertAsync({
file: e.currentTarget.files[0],
chunkSize: 'dynamic'
}, false);
upload.on('start', function () {
template.currentUpload.set(this);
});
upload.on('end', function (error, fileObj) {
if (error) {
alert(`Error during upload: ${error}`);
} else {
alert(`File "${fileObj.name}" successfully uploaded`);
}
template.currentUpload.set(false);
});
await upload.start();
}
}
});For multiple file upload see this demo code.
Upload base64 string (introduced in v1.7.1):
// As dataURI
await imagesCollection.insertAsync({
file: 'data:image/png,base64strβ¦',
isBase64: true, // <β Mandatory
fileName: 'pic.png' // <β Mandatory
});
// As plain base64:
await imagesCollection.insertAsync({
file: 'base64strβ¦',
isBase64: true, // <β Mandatory
fileName: 'pic.png', // <β Mandatory
type: 'image/png' // <β Mandatory
});For more expressive example see Upload demo app
To display files you can use fileURL template helper or link() method of FileCursor instance.
Template:
<template name='file'>
<img src="{{imageFile.link}}" alt="{{imageFile.name}}" />
<!-- Same as: -->
<!-- <img src="{{fileURL imageFile}}" alt="{{imageFile.name}}" /> -->
<hr>
<video height="auto" controls="controls">
<source src="{{videoFile.link}}?play=true" type="{{videoFile.type}}" />
<!-- Same as: -->
<!-- <source src="{{fileURL videoFile}}?play=true" type="{{videoFile.type}}" /> -->
</video>
</template>Shared code:
import { Meteor } from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';
const imagesCollection = new FilesCollection({ collectionName: 'images' });
const videosCollection = new FilesCollection({ collectionName: 'videos' });
if (Meteor.isServer) {
// Upload sample files on server's startup:
Meteor.startup(async () => {
await imagesCollection.loadAsync('https://raw.githubusercontent.com/veliovgroup/Meteor-Files/master/logo.png', {
fileName: 'logo.png'
});
await videosCollection.loadAsync('http://www.sample-videos.com/video/mp4/240/big_buck_bunny_240p_5mb.mp4', {
fileName: 'Big-Buck-Bunny.mp4'
});
});
Meteor.publish('files.images.all', function () {
return imagesCollection.collection.find();
});
Meteor.publish('files.videos.all', function () {
return videosCollection.collection.find();
});
} else {
// Subscribe to file's collections on Client
Meteor.subscribe('files.images.all');
Meteor.subscribe('files.videos.all');
}Client's code:
// imports/client/file/file.js
import '/imports/client/file/file.html';
import imagesCollection from '/imports/lib/collections/images.collection.js';
Template.file.helpers({
imageFile() {
return imagesCollection.findOne();
},
videoFile() {
return videosCollection.findOne();
}
});For more expressive example see Streaming demo app
Create collection available to Client and Server
// imports/lib/collections/images.collection.js
import { Meteor } from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';
const imagesCollection = new FilesCollection({ collectionName: 'images' });
if (Meteor.isServer) {
// Load sample image into FilesCollection on server's startup:
Meteor.startup(async () => {
await imagesCollection.loadAsync('https://raw.githubusercontent.com/veliovgroup/Meteor-Files/master/logo.png', {
fileName: 'logo.png',
});
});
Meteor.publish('files.images.all', function () {
return imagesCollection.collection.find();
});
} else {
// Subscribe on the client
Meteor.subscribe('files.images.all');
}Create template, call .link method on the FileCursor returned from file helper
<!-- imports/client/file/file.html -->
<template name='file'>
<a href="{{file.link}}?download=true" download="{{file.name}}" target="_parent">
{{file.name}}
</a>
</template>Create controller for file template with file helper that returns FileCursor with .link() method
// imports/client/file/file.js
import '/imports/client/file/file.html';
import imagesCollection from '/imports/lib/collections/images.collection.js';
Template.file.helpers({
file() {
return imagesCollection.findOne();
}
});For more expressive example see Download demo
- Where are files stored by default?: by default if
config.storagePathisn't set in Constructor options it's equals toassets/app/uploadsand relative to running script:- a. On
developmentstage:yourDevAppDir/.meteor/local/build/programs/server. Note: All files will be removed as soon as your application rebuilds or you runmeteor reset. To keep your storage persistent during development use an absolute path outside of your project folder, e.g./datadirectory. - b. On
production:yourProdAppDir/programs/server. Note: If using MeteorUp (MUP), Docker volumes must to be added tomup.json, see MUP usage
- a. On
- Cordova usage and development: With support of community we do regular testing on virtual and real devices. To make sure
Meteor-Fileslibrary runs smoothly in Cordova environment β enable withCredentials; enable{allowQueryStringCookies: true}and{allowedOrigins: true}on bothClientandServer. For more details read Cookie's repository FAQ - meteor-desktop usage and development: Meteor-Files can be used in meteor-desktop projects as well. As meteor-desktop works exactly like Cordova, all Cordova requirements and recommendations apply
- How to pause/continue upload and get progress/speed/remaining time?: see FileUpload instance returned from
insertAsyncmethod - When using any of
accountspackages - packageaccounts-basemust be explicitly added to.meteor/packagesaboveostrio:files - cURL/POST uploads - Take a look on POST-Example by @noris666
- In Safari (Mobile and Desktop) for
DDPchunk size is reduced by algorithm, due to error thrown if frame is too big. This issue should be fixed in Safari 11. Switching tohttptransport (which has no such issue) is recommended for Safari. See #458 - Make sure you're using single domain for the Meteor app, and the same domain for hosting Meteor-Files endpoints, see #737 for details
- When requests are proxied to
FilesCollectionendpoint make sure protocolhttp/1.1is used, see #742 for details
- Ask a question or submit an issue
- Releases / Changelog / History
- For more docs and examples read wiki
Fully-featured file-sharing app:
Other demos:
- pyfiles (meteor-python-files) Python Client for Meteor-Files package
- meteor-autoform-file - Upload and manage files with autoForm
- ποΈ Upload and share files using meteor-files.com β Continue interrupted file uploads without losing any progress. There is nothing that will stop Meteor from delivering your file to the desired destination
- π¨βπ» Improve your project using ostr.io for Server Monitoring, Web Analytics, WebSec, Web-CRON and SEO Pre-rendering
- π΅ Sponsor via GitHub
- π΅ Support via PayPal
- βοΈ Star on GitHub
- βοΈ Star on Atmosphere
- Want to help? Please check issues for open and tagged as
help wantedissues; - Want to contribute? Read and follow PR rules. All PRs are welcome on
devbranch. Please, always give expressive description to your changes and additions.
We would like to thank everyone who support this project
- @vanshady
- @Neophen
- @rikyperdana
- @derwok, check out his project - 4minitz
- @FinnFrotscher
- @Neobii
- @themeteorchef
- @MeDBejoHok
- @martunta