File Upload with Angular and Node.js

May 24, 2019
by Rahil Shaikh
  • node mysql tutorial

File Upload is one of those things that is not as straight forward but gets easier once we get our heads around it. In this tutorial, we will see how we can implement File Upload using Angular and Node.js. We have already covered Angular 1 variation of this topic in one of our previous tutorial.

This tutorial comprises of two parts.

  • Back-end with NodeJS/ ExpressJS and Multer
  • Browser Application with Angular 2 and ng2-File-Upload

Update: This article has been updated for Angular 7+.

Without further ado, let’s get started.

Back-end with NodeJS/ ExpressJS and Multer

The back-end implementation for File Upload with Node.js is more or less similar to the one we did in our post for file upload with Angular 1 and Node. There is only one change and that is we will be enabling CORS on our Node server. So here I’ll just display the code, for a detailed explanation please visit this link.


Let’s start by creating a project directory.

mkdir file-upload-demo

Now, let’s navigate into the working directory and create a directory for our Node.js application.

cd file-upload-demo
mkdir node-app

cd node-app
  "name": "expapp",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "gulp": "3.9.0",
    "gulp-develop-server": "0.5.0",
    "gulp-jshint": "1.12.0"
  "dependencies": {
    "body-parser": "1.14.1",
    "express": "4.13.3",
    "fs": "0.0.2",
    "multer": "1.1.0"
    var express = require('express');
    var app = express();
    var bodyParser = require('body-parser');
    var multer = require('multer');

    app.use(function(req, res, next) { //allow cross origin requests
        res.setHeader("Access-Control-Allow-Methods", "POST, PUT, OPTIONS, DELETE, GET");
        res.header("Access-Control-Allow-Origin", req.headers.origin);
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        res.header("Access-Control-Allow-Credentials", true);

    /** Serving from the same express Server
    No cors required */


    var storage = multer.diskStorage({ //multers disk storage settings
        destination: function (req, file, cb) {
            cb(null, './uploads/');
        filename: function (req, file, cb) {
            var datetimestamp =;
            cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1]);

    var upload = multer({ //multer settings
                    storage: storage

    /** API path that will upload the files */'/upload', function(req, res) {

    app.listen('3001', function(){
        console.log('running on 3001...');

We are using gulp as a task runner for our Node.js app.

var gulp   = require( 'gulp' ),
    server = require( 'gulp-develop-server' )
    jshint = require('gulp-jshint');
gulp.task('lint', function() {
  return gulp.src('app.js')
    // run server
gulp.task( 'server:start', function() {
    server.listen( { path: './app.js' } );
// restart server if app.js changed
gulp.task( 'server:restart', function() { [ './app.js' ], server.restart );

gulp.task('default', ['lint','server:start','server:restart']);


We need to have a directory where our uploaded files will go.

mkdir uploads

Install all dependencies, and also install gulp globally.

npm install

npm install gulp -g

We can start up the server with the below command.


If everything was setup properly you should be able to see the following output on the console.

File Upload with NodeJS

Node.js server

Browser Application with Angular and ng2-File-Upload

We will use the Angular CLI to bootstrap our application. Open up your terminal and type…

ng new angular-file-upload

We will be using ng2-file-upload library to help us with the File Upload for our Angular 2 application. Let’s install it using npm.

npm install ng2-file-upload --save


The ng2-file-upload module provides us with a few directives for achieving file upload, we need to import them and add them to the declaration of our AppModule before we can use them.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FileDropDirective, FileSelectDirective} from 'ng2-file-upload';

import { AppComponent } from './app.component';

  declarations: [
  imports: [
  providers: [],
  bootstrap: [AppComponent]
export class AppModule { }

We are importing and adding FileSelectDirective to the declarations, if we also want to implement the drag and drop feature we will have to add the FileDropDirective .

Basic Usage

In our app.component.ts we will import the FileUploader class and create an uploader object of type FileUploader.

import { Component } from '@angular/core';
import { FileUploader } from 'ng2-file-upload';

  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
export class AppComponent {
  title = 'angular-file-upload';
  public uploader:FileUploader = new FileUploader({url:'http://localhost:3001/upload'});

We are passing the upload URL of our Node.js application which we created earlier in the tutorial in the argument object of FileUploader.
To make this work in our template we will add a ng2FileSelect directive to an html input of type file, we will also set the [uploader] property to our uploader object.

For a single file, the input should look like below

<div class="form-group">
   <label for="single">single</label>
   <input type="file" class="form-control" name="single" ng2FileSelect [uploader]="uploader" />                                  

To enable selection of multiple files we only need to add the multiple attribute of HTML5.
The uploader object stores all the selected files in a queue. To upload all the file at once we can call uploader.uploadAll() function or we can call the upload() function availaible on each item of the queue.

<button type="button" class="btn btn-success btn-s"
    (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
    <span class="glyphicon glyphicon-upload"></span> Upload all
</button><br />

This much in your template should be enough to get the basic thing going, but it's not that presentable, so we will add a few more elements and try to make it more interactive. We are using bootstrap for styling, you are free to use a framework of your choice.

npm install [email protected] --save

Add the path to angular.json file in the styles array.

 "styles": [

Now let's create an interface to upload files.

The complete template file app.component.html would look like this.

<nav class="navbar navbar-default">
                    <div class="container-fluid">
                        <div class="navbar-header">
                        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                            <ul class="nav navbar-nav">
                            <li><a>File Upload</a></li>
                <div class="container">
                    <div class="row">
                        <div class="col-md-4">
                                <div class="form-group">
                                    <label for="multiple">Multiple</label>
                                    <input type="file" class="form-control" name="multiple" ng2FileSelect [uploader]="uploader" multiple  />
                                <div class="form-group">
                                    <label for="single">single</label>
                                    <input type="file" class="form-control" name="single" ng2FileSelect [uploader]="uploader" />                                  
                        <div class="col-md-8">
                            <h3>File Upload with Angular 2 and Node</h3>
                            Queue length: {{ uploader?.queue?.length }}

                            <table class="table">
                                    <th width="50%">Name</th>
                                <tr *ngFor="let item of uploader.queue">
                                    <td><strong>{{ }}</strong></td>
                                    <td nowrap>{{ item.file.size/1024/1024 | number:'.2' }} MB</td>
                                        <div class="progress" style="margin-bottom: 0;">
                                            <div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div>
                                    <td class="text-center">
                                        <span *ngIf="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
                                        <span *ngIf="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
                                        <span *ngIf="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
                                    <td nowrap>
                                        <button type="button" class="btn btn-success btn-xs"
                                                (click)="item.upload()" [disabled]="item.isReady || item.isUploading || item.isSuccess">
                                            <span class="glyphicon glyphicon-upload"></span> Upload
                                        <button type="button" class="btn btn-warning btn-xs"
                                                (click)="item.cancel()" [disabled]="!item.isUploading">
                                            <span class="glyphicon glyphicon-ban-circle"></span> Cancel
                                        <button type="button" class="btn btn-danger btn-xs"
                                            <span class="glyphicon glyphicon-trash"></span> Remove

                                    Queue progress:
                                    <div class="progress" style="">
                                        <div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
                                <button type="button" class="btn btn-success btn-s"
                                        (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
                                    <span class="glyphicon glyphicon-upload"></span> Upload all
                                <button type="button" class="btn btn-warning btn-s"
                                        (click)="uploader.cancelAll()" [disabled]="!uploader.isUploading">
                                    <span class="glyphicon glyphicon-ban-circle"></span> Cancel all
                                <button type="button" class="btn btn-danger btn-s"
                                        (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
                                    <span class="glyphicon glyphicon-trash"></span> Remove all

As I said earlier each file is stored in a queue. Hence, we are repeating through the queue using the ngFor directive. Each item has the following important properties.

  • file- File object which contains details related to respective file, including name, size and more.
  • progress- Progress of the item beign uploaded in percentage.
  • upload()- Method to upload the file.
  • cancel()- Cancels and ongoing upoad.
  • remove()- Removes item from queue.

And there are a few more properties. Have a closer look at the template to understand them. Apart from the properties and methods on each item we also have methods that operate on the entire queue. For eg: uploadAll(), cancelAll(), removeAll().

Also, please note when we are uploading multiple files together, it does not send all files at once, instead the ng2-file-uploader calls the upload API multiple times depending on the number of items, uploading one at a time.

To start the application run the below command.

ng serve

If you've followed along properly you should see the following screen on your browser running at localhost:3000.

File Upload Angular 2

Before Upload

Considering you have the Node.js app running, you should be able to upload files.

File Upload Angular 2

After Upload

Quick Setup

We know this has been a long tutorial and there are chances you might have slipped at one or two places. No worries, you can quickly get the demo running by following the below steps.

  • git clone file-upload
  • Navigate into the node app cd file-upload/node-app
  • Install Dependencies npm install
  • Install gulp globally npm install gulp -g
  • To start the node server gulp
  • Open a new terminal window.
  • Navigate into /angular-updated/
  • Install all dependencies npm install
  • In some cases you might have to isntall lite-server globally npm i lite-server -g
  • Run the Angular app using npm start



File Upload is one of the most common requirements for any web-application and sometimes it can become a hiccup, but not after this tutorial. In this tutorial, we learned how we can implement File Upload using Node.js and Angular with ease.

More Angular Stuff

  1. Angular Official Documentation
  2. Learn Angular 2 From our Free Video Course on YouTube


Engineer. Blogger. Thinker. Loves programming and working with emerging tech. We can also talk on Football, Gaming, World Politics, Monetary Systems.

Get notified on our new articles

Subscribe to get the latest on Node.js, Angular, Blockchain and more. We never spam!
First Name:


  1. mohit

    Great Tutorial Rahil…How can we maintain a list of who has uploaded what and then give the user a chance to delete the uploaded file as well?

    • |

      You will need to persist the metadata in some db. And display it when user demands.
      Metadata might include (path to image or blob, size, type, resolution, etc etc)

  2. |


    excelente post.

    How can I get the response from the upload?

    to have the file name or the path

    • |

      where would you want the path and filename? At the backend or in Angular2 app?

      • |

        Yes, I want to store in a record in the db with other data.

        • |

          The req.file object will have all the details!

          • |

            ok , but How can I can get the req from the uploader? (I’m using the single upload)

          • |

            Have a look at this peice of code.

  '/upload', function(req, res) {
  3. |

    ok , but I’ve to implement a function in a service with an observable to map the response , isn’t it?

    maybe I miss something


    • |

      I think you want to have the data at the client side then? Basically as a response from the upload api?
      Try this piece of code then.

       this.uploader.onSuccessItem = (item:FileItem, response:string, status:number, headers:ParsedResponseHeaders) => {
          console.log("onSuccessItem " + status, item);
  4. |

    great tutorial. but i tried uploading using “ONCHANGE” event and gives me error of “can not read property upload of undefined”. want your help sir

  5. kamal

    Get this error :

    Error: Template parse errors:
    Can’t bind to ‘uploader’ since it isn’t a known property of ‘input’. (“l for=”single”>single
    ][uploader]=”uploader” />

  6. Alan

    thank you for the tutorial but how can i save the file in a local folder? i tried to change the url:’/public’ and i created a public folder in app folder and the error of 404 i get

  7. Amitava

    Hi Rahil ,
    is it necessary to have backend server ? I am with angular 4 and i don’t need to transfer the file to a remote back-end server . In my use case after i click on Upload button i want to parse the file data and if it’s has valid content then i want to save/store the file in my angular client server only.

    What is your advice to achieve that ?

    • |

      @rahil can i expect reply for @Amitava question? BCZ i also have same reuirement

      • |

        Yes, in that case, you can avoid the backend server. But whatever format you are parsing should be supported by javascript in the browser.

  8. Sebastian

    How can I save a json with file metadata?, How this json can be actualized with other file metada when I post new files?

  9. Frank Segarra

    Great tutorial. Was able to port to my c# API with no problems. My api saves the file to a folder and then adds a row to a db table with values associated with the file (path, filename, size, …). I’m trying to add a field to the form and send it with the file. I modified the html slightly hoping to be able to pick up the title and save it in the db. Is this possible?

    • |

      Your code snippet is not properly displayed. Use code tags to ad code.

      //like this
      • |

        Hi rahil image upload process is not shown.. i have done some changes for rxjs and typescript. reason is that typescript 2.3.3 is only working.

  10. |

    What if I want to send some data from angular application to set the file name to the upload function?

  11. |

    Hi Sir
    First Thank you for this awesome post, this really gave me a point to start.
    But my issue is after I deployed the app to Heroku I can’t upload the files and I get 422 unprocessable entity error.
    Do you have any Idea how to solve this?
    PS: I did the same implementation as you did in this tuto.

  12. |

    Thanx for the great work, it really help alot.
    Am having this weird problem, and ave seen fellow developers asking over the same, its good we have several modules to hundle uploading files, and yes they work fine, but there is no a single post or tutorial on how to add text fields along the file upload. lets say i want angular 2 blog i will obliviously want to add title, description, the body or main content and add an image to accompany the blog post. in my case using an uploader like ng2-file uploader then after the image is uploaded in a specified folder like say /uploads what next???? how do i save the image path along the text field for the blog post in say mongoDB so when i display the article for the world to see , everthing i typed appears including the image i uploaded..a good example is twitter, you choose an image and add some text and boom! it is retrieved with image and text u typed..i have used google stack overflow and even open source projects and seems no single help for doing so all i see is blogs with text fields only and no ways of including and serving images for the so called blogs….any help is greatly appreciated. Thank you..

    • |

      Thanks Geniuso, in your efforts for posting this.
      Yea a lot of people come up with this issue, and I answer them individually. I think it’s time that I implement this with an example and link it to this article.
      So, as soon as I find some time I’ll add an example to my github and share it with you.

      Also, since you mentioned MongoDB, if you are comfortable with storing images into the database, make sure to check out my other article on File Upload with Node.js and GridFS.

  13. |

    Is there a way to add headers to the request?
    Im trying to upload a file from localhost:4200 to localhost:3000 but it says im not allowed to do that.

  14. |

    But how can I send my own data, forexamle, comments with the file???

  15. |

    hi rahil, i’ve followed every single step and at node.js server, it said running on 3001. but when i tried to open 3001, it said cannot GET.

  16. |

    thank you for your tutorial, it was helped me to sent image but i can’t send image along with text fields,
    how to post image field along with text fields, like i want to send form which will contain name, email and profile_pic….could you please help me out

  17. |

    Thanks for the great work, it really help a lot.
    I am working on MEAN stack application.
    I am able to upload word file in uploads folder.
    I want to save NAME OF WORD FILE along with CURRENT MONTH NAME in uploads folder in back end.
    I tried following code :
    var storage = multer.diskStorage({
    destination: function (req, file, cb) {
    cb(null, ‘./uploads/’);
    filename: function (req, file, cb) {
    var datetimestamp =;
    cb(null, file.originalname.split(‘.’).slice(0, -1).join(‘.’) + “-” + b[1]) //filename-monthname

    But it is changing the format of the file in uploads folder ?
    Do you have any Idea how to solve this ?

Leave a Comment