One of Meteor’s biggest selling point is the way it blurs the line between client and server.

With Meteor, these two environments are no longer separate worlds: they share a common language, and can even share common code!

But that blurring of lines comes at a cost: it can sometimes be tricky to figure out what should run where.

Client vs Server

Let’s start from the beginning. Meteor runs using the JavaScript language, which is unique among (nearly) every other programming languages in that it can be executed by browsers. In other words, Chrome, Safari, Firefox and all their friends can look at a bit of JavaScript code and make sense of it.

Try that with Ruby, Python, or C, and your browser will just look at you with a puzzled look on its face.

But wait! Browsers are not the only ones that can execute JavaScript code. So can servers, thanks to Node.js.

This is where Meteor comes in: by providing layers on top of both the server and the client, Meteor can bridge the gap and make the two sides talk to each other more smoothly.

Meteor’s Control Methods

Meteor gives you three basic ways of controlling where a file is executed:

  • In your app, you can use the /client and /server directories to restrict a file to only run in a specific environment.
  • In packages, you can pass "client" or "server" as arguments to the api.addFile() function to only load a file in a specific environment.

You can also control where a code block inside a file is executed (supposing the file itself runs in both environment) thanks to the Meteor.isClient and Meteor.isServer booleans.

For this article, we’ll only focus on the first scenario: controlling where a file is loaded using the /client and /server directories.

Meteor’s File Architecture

It’s also important to point out that Meteor doesn’t really care where you put your code past the client/server/both distinction. In other words, there is no practical difference between putting your code in foo/bar.js and putting it in bar/foo.js.

That being said, if you need a little more structure we recommend checking out Microscope to see what a “typical” Meteor app looks like.

[Client] Browser-Specific JavaScript

One of the first JavaScript function you’ll encounter when learning the language is the humble alert():

alert("Hello world!");

You can test this right now if you’d like; all it does is pop open a system dialog containing the string you passed as argument.

Now here’s a question for you: if I log on to my server, open a Node.js console, and feed it this line of JavaScript code, where will the alert show up?

If your answer was something along the line of “What!? That doesn’t make any sense!” then congratulations, you got it right. This was a trick question: alert() is clearly something that only makes sense in the context of the browser, since it needs a system to open the dialog, a screen to render it on, and a user to close it.

Now consider the following, used to set the scroll position of the body of a page to 300px from the top:

$("body").scrollTop(300);

A perfectly valid bit of JavaScript code (jQuery code, to be exact), yet one that makes no sense in the context of the server. The server has no concept of window, body, or scrolling. It’s just a dumb box sitting in the middle of some data center!

Hopefully you’re starting to see the pattern: any JavaScript code that specifically targets the browser should only run on the client (note that subscriptions also fall in this category).

The server has no clue what this thing is

[Client] User-Specific JavaScript

Additionally, there’s another category of code that should only run on the client: code that targets the current user.

Again, it makes sense if you think about it: the server is in charge of serving your app to hundreds, if not thousands of users. It doesn’t have a “current” user.

The Method Exception

The only exception to the “server doesn’t know about the user” rule is Meteor Methods.

A Method is a function that runs on the server, but is called from the client. This means the server knows which specific user made the call, and this is why Meteor.user() and Meteor.userId() (as well as the equivalent this.userId) can be used inside Methods code, even on the server.

There’s another Meteor feature that’s specific to the current user: Session variables.

In fact, the same can be said about client-side variables in general: even if client-side variables were somehow sent back to the server (and they aren’t), it wouldn’t really make sense. If Alice defines x equal to foo but Bob sets it equal to bar, how is the server supposed to know which one to use?

Alice and Bob arguing about what the value of x should be

[Client] Templates & Stylesheets

Although this might change in the future, both templates and stylesheets are currently only executed on the client.

By extension, this also means any template-related JavaScript code (such as template helpers, template callbacks, and event handlers) will only be executed on the client as well.

The one exception to this is email template: since emails are sent out by the server, you can use a package such as handlebars-server to define specific, server-only templates and styles.

[Both] Collections

So if templates, stylesheets, template-related code, user-specific code, and browser-related code all run on the client, what does that leave for the server?

A couple important things, as you’ll soon see. But before we can get there, we need to talk about code that needs to run on both the client and server.

The main example of this is collections code. Another one of Meteor’s innovations is the ability to mirror some of your data on the client, and this is done through the afore-mentioned collections.

For that reason, it makes sense to define collections in both environments (in other words, in any directory besides /client or /server). Of course, collection-related code (such as helpers or validation code) will also come along for the ride.

[Both] Methods

Meteor also features something called “optimistic UI” (a.k.a. latency compensation). This is a fancy way of saying that if an operation needs to involve the server (which would necessarily slow it down), the client will try to complete that operation by itself first, and then amend the result if needed once it gets the server’s actual reply.

Yet this can only happen if the client knows what the operation consists of, which is why method code is often shared among both environments.

[Server] Secure Data

Finally, we get to the server, and just the server.

Unlike the client, the server has direct access to your whole database, which gives it more control over your data.

For example, one of the main tasks of the server is publishing data to the client. This is done through publications, which are server-only. Since publications control which subset of your data should be made public (and which subset should remain secure), it stands to reason that this is not something you want your users to be able to control.

In fact, generally speaking any operation that involves private data like email addresses or API keys will be best handled by the server. After all, you wouldn’t want to expose that data to any random user!

[Server] Time-Sensitive Operations

Finally, another category of server-only operations is anything involving time: it’s trivial for a user to fake their browser’s time (not to mention the mess involved with timezones), so you can’t rely on it for any serious timekeeping.

So cronjob-type operations that needs to happen at regular intervals, rate-limiting, and timestamping should all be left to the server.

A Real-World Example

Let’s bring all of this together by looking at the code of Microscope, the app that you build in Discover Meteor.

Client

First, the client directory contains the following items:

  • helpers contains global template helpers and code for other client-only features such as error messages.
  • stylesheets contains the app’s styles.
  • templates contains the app’s templates as well as their companion JavaScript code, split into subgroups.
  • main.html and main.js hold the app’s main template and its code.

Both

The lib folder contains files shared across client and server:

  • collections contains the code for the Posts, Comments, and Notifications collections.
  • permissions.js contains code used to define who can do what, which applies both to client and server.
  • router.js deals with client-side and server-side routes.

Server

And finally, server contains server-only code:

  • fixtures.js contains code that will seed our database with content the first time we run the app.
  • pubications.js contains our publication code.

Conclusion

This is by no means meant to be an exhaustive list of every single use case you’ll encounter while building Meteor apps.

So I strongly recommend checking out the Meteor documentation whenever you’re not sure if something should run on the client, server, or both.

But hopefully, it will be enough to give you a few tools to help you figure things out the next time you’re stuck at that “Save As…” dialog wondering where to put your code.