A BrowserSync Primer

A relevant ad will be displayed here soon. These ads help pay for my hosting.
Please consider disabling your ad blocker on Pony Foo. These ads help pay for my hosting.
You can support Pony Foo directly through Patreon or via PayPal.

BrowserSync is a browser testing tool, similar to LiveReload. It also synchronizes across browsers and is going to provide HTML injection in the very near future, alongside with the CSS and JavaScript injection it already features.


This tool enables rapid continuous development by saving you the trouble of refreshing the view you are debugging whenever you make changes to the JavaScript or CSS code.

You won’t really be able to grasp how valuable this is until you give it a try for yourself. This primer aims to encourage you to do just that!

In this article I’ll show you how to use it with your favorite tools. Grunt, Gulp, npm run and nodemon.

Modern web development is burdened with quite a few pauses, such as saving files, running build tasks, refreshing the browser, besides the usual thinking and refactoring that you were used to. Continuous development helps you bridge the gap by shortening those pauses, or at least automating them in such a way that you don’t have to manually take action in between those pauses.

It doesn’t matter what tools you use, as long as those tools get you one step closer to true continuous development, eliminating the friction in between your changes and the result displayed on the browser.

  • Using a reasonable text editor (Sublime, Atom, vim, etc) you can auto-save when your tabs lose focus
  • Using watch tasks you can avoid restarting your build flow whenever source code changes
  • Using Nodemon you can avoid running node app whenever server-side code changes
  • Using BrowserSync you can avoid hitting F5 on the browser whenever client-side code changes

The one unfortunate drawback to BrowserSync is that currently its documentation is quite lacking. Rather than explain and document what the API does and what properties, options and methods there are, you just get a few use cases and the example code that goes with them.

Hopefully, their documentation will improve in the future. For now, you can rely on the guides in this article.

Using Grunt

If you’re using Grunt in your builds, you can use the grunt-browser-sync package. I’ll go ahead and assume you’re using load-grunt-tasks to load your tasks automatically.

npm install grunt-browser-sync --save-dev

Typically you’ll want the proxy behavior. In this case you can mount BrowserSync to listen on a port, but proxying an existing app. This will use your own server to respond to requests, but it’ll patch it with the appropriate script injection code, which is used on the client-side to reload CSS and JS through BrowserSync.

Besides configuring the server, BrowserSync needs to understand what files changes are going to trigger updates, and you can use a globbing pattern for that. Refer to the code snippet below for an example on how to configure grunt-browser-sync.

browserSync: {
  dev: {
    bsFiles: {
      src: 'public/**/*.{js,css}'
    options: {
      proxy: 'localhost:3000'

When you are using watch tasks, you are expected to set the watchTask option to true.

Using Gulp

When using Gulp, the folks at BrowserSync recommend using the browser-sync API directly, rather than a plugin, and for good reason. The code is pretty self-explanatory, simplicity beats over-engineering.

var gulp = require('gulp');
var browserSync = require('browser-sync');

gulp.task('browser-sync', function () {
    proxy: 'localhost:3000',
    files: ['public/**/*.{js,css}']

Doing the same with npm run is even easier.

browser-sync start --proxy localhost:3000 --files "public/*"

In my experience, though, at this point you are better off using the API within your Node application.

Inside a Node application

The upside in running BrowserSync directly in your app is that you won’t bash your head against the wall when attempting to make it play nicely with tools such as nodemon, which constantly restart the server that BrowserSync is proxying.

To ensure that the server is always up when BrowserSync attempts to uplink, I find that the best approach is to configure it as follows.

var express = require('express');
var browserSync = require('browser-sync');
var app = express();
var port = process.env.PORT || 3000;

app.listen(port, listening);

function listening () {
    proxy: 'localhost:' + port,
    files: ['public/**/*.{js,css}']

Now you can run nodemon and BrowserSync will work even across restarts. Yay!

nodemon app.js

It’s time to focus on what really matters.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.