By Joseph Silber


2010-09-08 06:24:18 8 Comments

Is there any way I can create a text file on the client side and prompt the user to download it, without any interaction with the server? I know I can't write directly to their machine (security and all), but can I create and prompt them to save it?

20 comments

@darrell 2019-11-14 19:09:10

I would use an <a></a> tag then set the href='path'. Afterwards, place an image in between the <a> elements so that I can have a visual to see it. If you wanted to, you could create a function that will change the href so that it won't just be the same link but be dynamic.

Give the <a> tag an id as well if you want to access it with javascript.

Starting with the HTML Version:

<a href="mp3/tupac_shakur-how-do-you-want-it.mp3" download id="mp3Anchor">
     <img src="some image that you want" alt="some description" width="100px" height="100px" />
</a>

Now with JavaScript:

*Create a small json file*;

const array = [
     "mp3/tupac_shakur-how-do-you-want-it.mp3",
     "mp3/spice_one-born-to-die.mp3",
     "mp3/captain_planet_theme_song.mp3",
     "mp3/tenchu-intro.mp3",
     "mp3/resident_evil_nemesis-intro-theme.mp3"
];

//load this function on window
window.addEventListener("load", downloadList);

//now create a function that will change the content of the href with every click
function downloadList() {
     var changeHref=document.getElementById("mp3Anchor");

     var j = -1;

     changeHref.addEventListener("click", ()=> {

           if(j < array.length-1) {
               j +=1;
               changeHref.href=""+array[j];
          }
           else {
               alert("No more content to download");
          }
}

@NVRM 2019-07-31 22:54:38

We can use the URL api, in particular URL.createObjectURL(), and the Blob api to encode and download pretty much anything.

document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify("HELLO WORLD", null, 2)]))}"> Click me</a>`
download.click()
download.outerHTML = ""

Bonus! Download any cyclic objects, avoid the errors:

TypeError: cyclic object value (Firefox) TypeError: Converting

circular structure to JSON (Chrome and Opera) TypeError: Circular

reference in value argument not supported (Edge)

Using https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

/* JSON.decycle */
if(typeof JSON.decycle!=="function"){JSON.decycle=function decycle(object,replacer){"use strict";var objects=new WeakMap();return(function derez(value,path){var old_path;var nu;if(replacer!==undefined){value=replacer(value)}
if(typeof value==="object"&&value!==null&&!(value instanceof Boolean)&&!(value instanceof Date)&&!(value instanceof Number)&&!(value instanceof RegExp)&&!(value instanceof String)){old_path=objects.get(value);if(old_path!==undefined){return{$ref:old_path}}
objects.set(value,path);if(Array.isArray(value)){nu=[];value.forEach(function(element,i){nu[i]=derez(element,path+"["+i+"]")})}else{nu={};Object.keys(value).forEach(function(name){nu[name]=derez(value[name],path+"["+JSON.stringify(name)+"]")})}
return nu}
return value}(object,"$"))}}


document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify(JSON.decycle(document), null, 2)]))}"></a>`
download.click()

@giapnh 2019-02-25 02:29:59

This below function worked.

 private createDownloadableCsvFile(fileName, content) {
   let link = document.createElement("a");
   link.download = fileName;
   link.href = `data:application/octet-stream,${content}`;
   return link;
 }

@Carl Kroeger Ihl 2019-12-05 23:48:29

can you open the file in a new tab keeping the fileName assigned, but not downloading, just opening in a tab?

@Beau Smith 2019-02-04 23:17:34

The package js-file-download from github.com/kennethjiang/js-file-download handles edge cases for browser support:

View source to see how it uses techniques mentioned on this page.

Installation

yarn add js-file-download
npm install --save js-file-download

Usage

import fileDownload from 'js-file-download'

// fileDownload(data, filename, mime)
// mime is optional

fileDownload(data, 'filename.csv', 'text/csv')

@Brian Burns 2019-04-13 22:07:10

Thanks - just tested - works with Firefox, Chrome and Edge on Windows

@abdul 2018-10-17 10:13:23

For me this worked perfectly, with the same filename and extension getting downloaded

<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>

'title' is the file name with extension i.e, sample.pdf, waterfall.jpg, etc..

'file64' is the base64 content something like this i.e, Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO

@Mostafa 2017-05-17 10:55:18

As mentioned before, filesaver is a great package to work with files on the client side. But, it is not do well with large files. StreamSaver.js is an alternative solution (which is pointed in FileServer.js) that can handle large files:

const fileStream = streamSaver.createWriteStream('filename.txt', size);
const writer = fileStream.getWriter();
for(var i = 0; i < 100; i++){
    var uint8array = new TextEncoder("utf-8").encode("Plain Text");
    writer.write(uint8array);
}
writer.close()

@Brandon.Blanchard 2017-09-22 20:07:54

Text Encoder is highly experimental right now, I'd suggest avoiding (or polyfilling) it.

@naren 2013-11-25 13:37:45

All of the above example works just fine in chrome and IE, but fail in Firefox. Please do consider appending an anchor to the body and removing it after click.

var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['Test,Text'], {type: 'text/csv'}));
a.download = 'test.csv';

// Append anchor to body.
document.body.appendChild(a);
a.click();

// Remove anchor from body
document.body.removeChild(a);

@Matt 2014-12-16 19:44:47

However: there's an open bug in IE 10 (and I've still seen it in 11) that throws "Access is denied" on the a.click() line because it thinks the blob URL is cross-origin.

@inf3rno 2015-09-13 00:13:57

@Matt data uri is cross origin in some browsers. as far as I know, not just in msie, but in chrome as well. you can test it by trying to inject javascript with data uri. It won't be able to access other parts of the site...

@Kevin 2018-04-02 18:57:32

"All of the above example works just fine in chrome and IE, but fail in Firefox.". Since the order of answers can change over time, it's unclear which answers were above yours when you wrote this. Can you indicate exactly which approaches don't work in Firefox?

@Rick 2015-02-02 01:25:20

If you just want to convert a string to be available for download you can try this using jQuery.

$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));

@atfornes 2016-06-15 12:31:18

Scape data with encodeURI might be needed as I suggested here before being able to comment: stackoverflow.com/a/32441536/4928558

@Ludovic Feltz 2015-11-05 10:42:44

All the above solutions didn't work in all browsers. Here is what finally works on IE 10+, Firefox and Chrome (and without jQuery or any other library):

save: function(filename, data) {
    var blob = new Blob([data], {type: 'text/csv'});
    if(window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    }
    else{
        var elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;        
        document.body.appendChild(elem);
        elem.click();        
        document.body.removeChild(elem);
    }
}

Note that, depending on your situation, you may also want to call URL.revokeObjectURL after removing elem. According to the docs for URL.createObjectURL:

Each time you call createObjectURL(), a new object URL is created, even if you've already created one for the same object. Each of these must be released by calling URL.revokeObjectURL() when you no longer need them. Browsers will release these automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.

@LEM 2016-05-27 16:51:03

Thanks a million. I've tried all the examples listed here and only this one works with any browser. This should be the accepted answer.

@JackMorrissey 2016-07-05 16:29:43

In Chrome, I didn't actually have to append the element to the body to get this to work.

@gm2008 2016-08-11 16:48:06

There is a size limit. For Chrome, it is said to be 2MB. Anyone has idea on how to deal with larger file?

@Splaktar 2016-09-06 17:55:44

Calling window.URL.revokeObjectURL(elem.href); after removing elem on Firefox 48 results in the download window never appearing and the download never starting. Removing the call to revokeObjectURL() solves this. For AngularJS 1.x apps, I guess that you can build an array of Urls that are cleaned up on destroy of the controller.

@Splaktar 2016-09-06 18:12:46

For AngularJS 1.x apps, you can build an array of Urls as they are created and then clean them up in the $onDestroy function of the component. This is working great for me.

@Dan Dascalescu 2016-11-05 21:06:48

This combines naren's solution, with Dzarek's handling of IE.

@Tjorriemorrie 2017-01-04 02:11:57

What is data? is it encodeURI(content)?

@juniper- 2017-09-27 19:25:12

Other answers led to Failed: network error in Chrome. This one works well.

@Kevin 2018-04-02 18:57:06

"All the above solutions didn't work in all browsers". Since the order of answers can change over time, it's unclear which answers were above yours when you wrote this. Can you indicate exactly which approaches don't work in all browsers?

@Sam 2019-03-29 08:41:02

This worked for me in Chrome (73.0.3683.86), Firefox (66.0.2), IE11 (11.379.17763.0) and Edge (44.17763.1.0).

@WBT 2019-05-21 15:33:12

Kanchu's solution on the duplicate of this question includes some small improvements.

@t.stv 2019-10-28 17:10:10

that bypasses the URI size limit.

@Matthew Flaschen 2010-09-08 06:29:02

You can use data URIs. Browser support varies; see Wikipedia. Example:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>

The octet-stream is to force a download prompt. Otherwise, it will probably open in the browser.

For CSV, you can use:

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>

Try the jsFiddle demo.

@Darin Dimitrov 2010-09-08 06:32:09

This is not a cross browser solution but definitely something worth looking at. For example IE limits support to data uri. IE 8 limits size to 32KB and IE 7 and lower doesn't support at all.

@Matthew Flaschen 2010-09-08 06:35:37

@Darin, yes, this won't work in any version of IE, because data URIs are not allowed in a elements.

@Chris 2012-05-16 11:44:21

in Chrome Version 19.0.1084.46, this method generates the following warning : "Resource interpreted as Document but transferred with MIME type text/csv: "data:text/csv,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A"." A download is not triggered

@Matthew Flaschen 2012-05-16 14:53:39

@Chris, yes, apparently it doesn't work in Chrome, even with octet-stream.

@earcam 2012-08-30 16:20:17

It does work in Chrome now (tested against v20 and v21) but not IE9 (that might just be the jsFiddle, but somehow I doubt it).

@Joseph Silber 2012-11-09 19:56:19

I'm accepting this answer, since there seems to be no other way to accomplish this...

@Jean-Philippe Martin 2013-03-08 15:44:06

Does not work in ie8 and ie9 because these browsers only support data uri for images. Ref: stackoverflow.com/questions/12042847/…

@Teepeemm 2014-04-30 15:59:50

As naren noted with his answer, Firefox needs the link to be present in the document in order for the download to occur.

@jasongonzales 2014-07-02 15:35:59

Doesn't work at all in Safari (7.0.4). Also, as of Chrome 36.0.1985.97 beta it doesn't seem possible to name the file using the download attribute.

@Rudey 2014-09-11 13:47:55

Also, using Chrome 37.0.2062.120, the browser crashes when the base64 string gets too long.

@Milimetric 2014-09-12 18:41:11

I was like - who is that linking to wikipedia for browser compat - oh ok :)

@larspars 2014-11-19 09:06:50

The correct charset is almost certainly UTF-16, unless you have code converting it to UTF-8. JavaScript uses UTF-16 internally. If you have a text or CSV file, start the string with '\ufeff', the Byte Order Mark for UTF-16BE, and text editors will be able to read non-ASCII characters correctly.

@Matthew Flaschen 2014-11-20 01:10:32

@larspars, good point. It is possible to make a UTF-8 data URL (and my example was one), but probably easier to make a UTF-16 one. Technically, though, JavaScript is closer to UCS-2.

@Avinav 2015-05-22 15:53:20

Does not data URIs have size limitations?

@Matthew Flaschen 2015-05-30 23:16:06

@Avinav, yes, at least in certain browsers (e.g. IE 8).

@Sheraff 2015-11-22 15:35:58

if there a way to give an understandable name to an image whose src is a data URI?

@Alex 2015-12-22 14:49:42

Does not work in Samsung Browser (Default mobile browser)

@elshnkhll 2016-01-15 16:33:53

Just add download="txt.csv" attribute in order to have proper file name and extension and to tell your OS what to do with it.

@gm2008 2016-08-11 16:46:48

And there is a size limit. It is said that for Chrome, the limit is 2MB.

@Jerry 2016-11-22 21:53:57

Works like a charm on Chrome. base64 seems to be the best solution to pass PDF files :)

@FluorescentGreen5 2017-05-07 11:23:30

Using <a> attribute download="filename.txt" and javascript .click() you can automate the process.

@drinovc 2017-11-08 16:43:57

It does not work in Microsoft Edge 40.15063.674.0 and Internet Explorer 11.674.15063.0. I used the answer from @naren and it works.

@youcantryreachingme 2018-02-25 02:12:14

I'm trying to use this to download the value of a textarea as a text file but the newlines in the textarea are not shown in the downloaded text file. Suggestions? Here is how I form the href: 'data:application/octet-stream,' + encodeURIComponent(document.getElementById("editor").value).‌​replace("\n","%0A") . (I added the replace function hoping that might be the issue).

@James McLaughlin 2018-10-01 13:04:46

No longer works in Firefox; top level data URIs have been blocked for "security". bugzilla.mozilla.org/show_bug.cgi?id=1331351

@atfornes 2015-09-07 14:59:01

Based on @Rick answer which was really helpful.

You have to scape the string data if you want to share it this way:

$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));

` Sorry I can not comment on @Rick's answer due to my current low reputation in StackOverflow.

An edit suggestion was shared and rejected.

@Rick 2016-06-15 21:22:35

I was not able to accept the suggestion. Strange... I updated the code.

@Danielo515 2015-07-15 18:52:36

This solution is extracted directly from tiddlywiki's (tiddlywiki.com) github repository. I have used tiddlywiki in almost all browsers and it works like a charm:

function(filename,text){
    // Set up the link
    var link = document.createElement("a");
    link.setAttribute("target","_blank");
    if(Blob !== undefined) {
        var blob = new Blob([text], {type: "text/plain"});
        link.setAttribute("href", URL.createObjectURL(blob));
    } else {
        link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
    }
    link.setAttribute("download",filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Github repo: Download saver module

@Narxx 2017-02-16 16:26:57

It works very nicely on Chrome, but not on Firefox. It does make a file and downloads it, but the file is empty. No content. Any ideas why? Haven't tested on IE...

@Yoraco Gonzales 2018-08-20 20:32:47

except that the function has no name, this is my favourite

@Matěj Pokorný 2013-08-12 21:57:53

Simple solution for HTML5 ready browsers...

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}
form * {
  display: block;
  margin: 10px;
}
<form onsubmit="download(this['name'].value, this['text'].value)">
  <input type="text" name="name" value="test.txt">
  <textarea name="text"></textarea>
  <input type="submit" value="Download">
</form>

Usage

download('test.txt', 'Hello world!');

@Joseph Silber 2013-08-12 22:01:31

Yep. This is exactly what @MatthewFlaschen has posted here about 3 years ago.

@Matěj Pokorný 2013-08-12 22:08:25

Yes, but with download attribute you can specify file name ;-)

@Joseph Silber 2013-08-13 00:30:21

As @earcam has already pointed out in the comments above.

@Carl Smith 2014-07-19 14:34:17

Chrome only appends the txt extension if you do not provide an extension in the filename. If you do download("data.json", data) it'll work as expected.

@Scotow 2016-05-18 17:22:32

In chrome if I use your code outside a submit form, and named my file *.js for example, chrome tell me its a malware. Any idea how to fix this ?

@Matěj Pokorný 2016-05-19 13:48:52

@Scotow Same situation with this fiddle? Maybe this is related: Malware and unwanted software

@Gasp0de 2018-03-06 09:23:57

This will remove any newline in the downloaded text. My file only contains 1 line. Any Idea on how to fix that? If I do data:text/plain;base64 firefox won't download it.

@Matěj Pokorný 2018-03-06 09:49:41

@Gasp0de You are opening that file in Windows Notepad. Am I right? Try Sublime Text, VSCode, Atom, Notepad++, etc. Notepad expecting, that lines ends with sequence \n\r, but this method saves new lines as \n only.

@Gasp0de 2018-03-06 10:00:13

@MatějPokorný I am using Notepad++. I have also tried JSON.stringify(item, undefined, "\t").replace(/\n/g, "\r\n");. When I print the text on the console, immediately before inserting it into the data uri, I can see that it contains \r\n, however, when I open the saved file those are gone. I think I better open an own question.

@Gasp0de 2018-03-06 10:08:04

I opened an own question here: stackoverflow.com/questions/49128196/…

@Sam 2019-03-29 08:40:11

This worked for me in Chrome (73.0.3683.86), and Firefox (66.0.2). It did NOT work in IE11 (11.379.17763.0) and Edge (44.17763.1.0).

@chovy 2019-05-03 06:44:34

How can I do this with a jpeg or png file?

@Hardik Darji 2019-10-14 06:57:45

Does it work for Mobile App or Mobile browser? I have tried this for iPhone Safari browser, but It does not download the file in download folder

@sean 2019-12-06 14:04:05

There's no need to attach the element to the DOM.

@MANVENDRA LODHI 2015-05-09 11:36:20

var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' +      encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();

@Dan Dascalescu 2016-11-05 21:08:30

What are the differences between this approach and creating a Blob?

@pravin 2015-01-20 15:47:54

As of April 2014, FileSytem APIs may not be standardized in W3C. Anyone looking at the solution with blob should thread with caution, I guess.

HTML5 rocks heads up

W3C Mailing List on FileSytem API

@Dzarek 2013-11-08 10:32:25

Solution that work on IE10: (I needed a csv file, but it's enough to change type and filename to txt)

var csvContent=data; //here we load our csv data 
var blob = new Blob([csvContent],{
    type: "text/csv;charset=utf-8;"
});

navigator.msSaveBlob(blob, "filename.csv")

@Dan Dascalescu 2016-11-05 21:10:14

Ludovic's answer includes this big, plus support for the other browsers.

@dinesh ygv 2013-12-27 06:55:52

The following method works in IE11+, Firefox 25+ and Chrome 30+:

<a id="export" class="myButton" download="" href="#">export</a>
<script>
    function createDownloadLink(anchorSelector, str, fileName){
        if(window.navigator.msSaveOrOpenBlob) {
            var fileData = [str];
            blobObject = new Blob(fileData);
            $(anchorSelector).click(function(){
                window.navigator.msSaveOrOpenBlob(blobObject, fileName);
            });
        } else {
            var url = "data:text/plain;charset=utf-8," + encodeURIComponent(str);
            $(anchorSelector).attr("download", fileName);               
            $(anchorSelector).attr("href", url);
        }
    }

    $(function () {
        var str = "hi,file";
        createDownloadLink("#export",str,"file.txt");
    });

</script>

See this in Action: http://jsfiddle.net/Kg7eA/

Firefox and Chrome support data URI for navigation, which allows us to create files by navigating to a data URI, while IE doesn't support it for security purposes.

On the other hand, IE has API for saving a blob, which can be used to create and download files.

@dinesh ygv 2016-11-06 02:17:22

I just used jquery to attach events(onclick and onready) and set attributes, which you can also do with vanilla JS. The core part(window.navigator.msSaveOrOpenBlob) doesn't need jquery.

@flipperweid 2017-06-26 08:21:39

There is still the limitation of size for the data uri approach, isn't it?

@Daniel Buckmaster 2013-05-08 23:05:25

I'm happily using FileSaver.js. Its compatibility is pretty good (IE10+ and everything else), and it's very simple to use:

var blob = new Blob(["some text"], {
    type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");

@gregm 2013-05-22 18:40:23

This works great on Chrome. How do I allow the user to specific the location of the file on disk?

@notbad.jpeg 2013-06-19 21:16:05

Wow, thanks for the easy to use library. This is easily the best answer, and who cares about people using HTML < 5 these days any ways?

@Daniel Buckmaster 2013-06-20 06:23:07

@gregm I'm not sure you can with this plugin.

@CoDEmanX 2014-12-03 15:54:40

@gregm: You mean the download location? That's not related to FileSaver.js, you need to set your browser configuration so that it asks for a folder before every download, or use the rather new download attribute on <a>.

@TMc 2015-01-12 20:32:23

This is a GREAT solution for IE 10+ family of browsers. IE doesn't support the download HTML 5 tag yet and the other solutions on this page (and other SO pages discussing the same problem) were simply not working for me. FileSaver ftw!

@Alex 2015-12-22 14:46:21

It does not work in Samsung Browser 3 (Default browser on at least Galaxy 6)

@Ryan Lee 2017-01-13 01:18:10

@CoDEmanX how do you set the attribute? All I see is a function call...

@CoDEmanX 2017-02-11 11:23:47

I was referring to <a download="...">. I'm not sure if/how FileSaver.js supports this.

@Maxim 2017-05-30 15:31:56

It looks like demo reloads page. History in dev tools is updated. Binary octect looks better as solution.

@owencm 2013-04-06 21:08:22

You can even do one better than just URI's - using Chrome you are also able to suggest the name the file will take, as explained in this blog post about naming a download when using URIs.

@Joseph Silber 2013-04-07 08:46:41

@HBP 2010-09-08 06:51:27

If the file contains text data, a technique I use is to put the text into a textarea element and have the user select it (click in textarea then ctrl-A) then copy followed by a paste to a text editor.

@Joseph Silber 2010-09-08 07:07:59

I had considered that, but from a user-friendliness point, this is disastrous. Also, the file has to be saved with a CSV extension. Try telling that to your users.

Related Questions

Sponsored Content

37 Answered Questions

[SOLVED] How do I check whether a file exists without exceptions?

33 Answered Questions

[SOLVED] How can I upload files asynchronously?

19 Answered Questions

[SOLVED] How do you use a variable in a regular expression?

  • 2009-01-30 00:11:05
  • JC Grubbs
  • 685726 View
  • 1253 Score
  • 19 Answer
  • Tags:   javascript regex

58 Answered Questions

[SOLVED] How do I include a JavaScript file in another JavaScript file?

38 Answered Questions

[SOLVED] How do I loop through or enumerate a JavaScript object?

28 Answered Questions

[SOLVED] How to read a file line-by-line into a list?

23 Answered Questions

[SOLVED] Event binding on dynamically created elements?

9 Answered Questions

[SOLVED] What is JSONP, and why was it created?

19 Answered Questions

[SOLVED] Download a file by jQuery.Ajax

17 Answered Questions

[SOLVED] How to decide when to use Node.js?

Sponsored Content