Essential Meteor Performance Tips

Meteor is the one of the easiest and robust ways to build real-time web apps. But Meteor is also known for bad performance. This is half true and half false. But that doesn't mean Meteor cannot be used in production or cannot be scaled.

Recently, I've worked on some improvements which make Meteor production ready. I hacked into Meteor and changed some of the internals to make it perform better. Also, I've tried and tested several proven web scaling techniques with Meteor and the results were promising. All of my hacks and findings are blogged at MeteorHacks.

In this article, I'll show you a series of tips which can be used to make your Meteor app perform better and make it production ready. Let's begin.

Use Smart Collections

The current MongoDB implementation in Meteor is not performing well. Meteor does have some plans to make it better, but we are not there just yet.

Smart Collections is a totally redesigned collection implementation for Meteor. It is well tested and used in production. You can get five times the performance improvements with Smart Collections. If you've got more subscriptions, Smart Collections gives you even more performance.

Smart Collections is almost compatible with the current Meteor Collection implementation. So it is a drop in replacement, you don't need to change any application specific code. Here is how you can use Smart Collections in your app.

Install It From Atmosphere

Replace Meteor Collections With Smart Collections

Additionally, Smart Collections has support to scale Meteor apps horizontally and it is currently the best solution.

Think About MongoDB Indexes

When developing your applications, I know alot of you out there simply don't care about MongoDB. You just focus on the app. Now, this is not a bad thing and this is also why Meteor is so popular. But, before you put your app into production, you must look into the queries you've used and add proper indexes for them.

You must add correct indexes, otherwise things will get even worst (this totally depends on your app and how people are using your app).

Read this official MongoDB index guide and choose correct indexes for your app. Additionally, you can profile MongoDB for slow queries and decide where you need to focus.

Arrays and Nested Objects

Meteor's real-time engine identifies changes based on the fields of the MongoDB document. But it does not support nested fields and arrays. For example, let's look at the following MongoDB document.

If you were to update country to a new value, Meteor detects this as a change to the address not to address.country. So Meteor will send a full object assigned to address, to the client.

Similarly, if you've added an item to projects, the whole projects array will be sent back to the client.

For a small document like above, this is not a big problem. But if your document contains lots of nested content and large arrays, think twice.

Filter Only the Fields You Need

When creating a publication only filter fields that need to be sent to the client. This saves bandwidth and the client will only get the fields which they really need. This might also fix the problem addressed in the previous tip.

See following example. It only sends type, content and _id to the client.

Think About Subscriptions

Meteor keeps a copy of each document related to each subscription on the server. This caching allows Meteor to send exact changes of the document to the client, and it saves bandwidth. As a result of this, the server's RAM usage might increase with the number of subscriptions you have.

So, it is wise to stop subscriptions that you don't need in order to get optimal RAM usage.

If your RAM usage is getting fat, this might be the problem. Keep an eye on this.

Use Meteor Streams When Persistence Is Not Needed

Meteor's real-time model builds on top of MongoDB. That means you are persisting all of your communication to the DB. Now, this isn't bad, but not every real-time communication needs to be persisted to the DB. For those things, you can use Meteor Streams. Meteor Streams adds real-time messaging capabilities to Meteor.

Disable WebSockets If Not In Use

When a client is trying to establish a connection to the Meteor Server, first it tries with WebSockets. If that fails, then it will try some other technique like xhr-polling.

Your Meteor app or most of the users may stay behind a firewall or a proxy that does not speak WebSockets. In those situations, the above process takes time and it will slow down how fast your app loads for the client.

The solution is to disable WebSockets in your app. This way clients will never try for WebSockets and instead, they will use some other proven technique which works everywhere. To do this, use the DISABLE_WEBSOCKETS environmental variable as shown below.

DISABLE_WEBSOCKETS=true Meteor

Don't Serve Static Content From Meteor

In the end, Meteor runs on top of NodeJS. As we all know, NodeJS is not that great at serving static content. So if your app largely depends on static content, it would be wise to serve them from a CDN or a proxy, like Nginx. How to do this though is out of the scope of this article. But these guides will get you there.

Conclusion

So that completes my series of Meteor performance tips. Go ahead and apply some of these to your app and see what kind of improvements you get. If you know of any other tips and tricks, which make Meteor perform better, please do share them with us.