Backbone.js View Lifecycle

Written by Backbone Tutorials Team

Last updated: June 2026 · 10 min read

The first time you render a Backbone view it looks perfect. Then a model updates, you re-render, and suddenly clicking a single button fires its handler three times, or two copies of the same row sit stacked in the DOM. Nothing is broken, exactly; the view just never learned how to grow up and clean up. That arc, from creation to teardown, is the view lifecycle, and getting it right is the difference between a tidy interface and a slow memory leak.

This guide walks the whole arc with code you can run. It assumes you have met the View already and have read the events guide, since the safe parts of the lifecycle lean directly on listenTo.

The Backbone view lifecycle A view is created, then rendered, re-renders on model changes, and is finally removed. new View() initialize render() build el remove() stopListening re-render on change create teardown
Four beats: create the view, render it once, re-render whenever its data changes, then remove it cleanly.

el, $el, and where a view lives

Every Backbone view owns exactly one DOM element, exposed as this.el. If you do not supply one, Backbone builds it from the view's tagName (defaulting to a div), plus any className or id you set. Alongside it sits this.$el, the same node wrapped in jQuery for convenience.

Letting Backbone create el versus binding to existing markup

var Row = Backbone.View.extend({
  tagName: 'li',
  className: 'todo'
});

var row = new Row();
console.log(row.el.outerHTML);
// => <li class="todo"></li>

The element exists immediately, even before you render anything into it. If instead you want a view to take over markup already on the page, pass el when you create it (for example new Row({ el: '#existing' })), and Backbone wires $el to that node rather than making a new one.

render(): your one job, done well

Here is the fact that surprises newcomers: Backbone never calls render for you. It is a convention, an empty method you are expected to fill in and invoke yourself. A good render does two things: it puts markup inside this.$el, and it returns this.

Why render should return this

render: function () {
  this.$el.html(this.template(this.model.toJSON()));
  return this; // lets a parent chain: container.append(view.render().el)
}

Returning this is not decoration. It lets a parent view write this.$el.append(child.render().el) in a single readable line, which is the standard way list views attach their rows. Skip the return and that pattern quietly breaks.

The events hash and delegateEvents

User input is declared, not wired by hand. The events hash maps a DOM event and an optional selector to a method name, and Backbone attaches them for you when the view is created.

How delegation survives re-rendering

var Toggle = Backbone.View.extend({
  events: {
    'click .done': 'markDone'
  },
  markDone: function () { this.model.set('done', true); }
});

The important detail is where Backbone listens. It binds the handler to the view's root element and lets the click bubble up from .done, a technique called delegation. Because the binding lives on the root, not on the inner markup, replacing that inner markup during a re-render does not detach it. The handler keeps working without you lifting a finger.

Re-rendering without duplicating anything

Most lifecycle pain is really one mistake: adding markup on re-render instead of replacing it. Run the first version below twice and you get two copies; the second version is idempotent, so calling it any number of times leaves one clean result.

Replacing innerHTML versus appending

// Trap: each call stacks another copy inside the element
render: function () { this.$el.append(this.template()); return this; }

// Fix: replace the contents every time
render: function () { this.$el.html(this.template()); return this; }

Pair the idempotent version with a listener, this.listenTo(this.model, 'change', this.render), and the view repaints itself whenever its data changes, always to a single correct state. For views that contain child views, remember to remove the children before rebuilding, or the page keeps the old ones alive offscreen.

remove(): clean teardown in one call

When a view leaves the screen, it should leave memory too. Backbone gives you one method for that: remove. It detaches el from the document and calls stopListening, releasing every subscription the view made with listenTo.

What remove() does for you, and when to extend it

var Panel = Backbone.View.extend({
  initialize: function () {
    this.listenTo(this.model, 'change', this.render);
  },
  remove: function () {
    // tidy up child views or plugins first
    Backbone.View.prototype.remove.call(this);
  }
});

panel.remove(); // element detached + stopListening() called

For a simple view the built-in remove is enough. Once a view owns child views, jQuery plugins, or timers, override remove, clean those up first, then call the original with Backbone.View.prototype.remove.call(this). Forgetting this is the classic source of the zombie views covered in the events guide.

The lifecycle in modern terms

If you have used a newer framework, this rhythm will feel familiar, because the industry kept the beats and only changed who keeps time. A Backbone view's create, render, and remove line up almost exactly with the mount, update, and unmount phases other libraries expose.

Mount, update, and unmount across frameworks

React talks about mounting, re-rendering on state change, and unmounting; Vue names them mounted, updated, and unmounted. Backbone simply makes you press the buttons yourself. Learn the manual version here and the automatic versions elsewhere stop feeling mysterious, because you can see exactly which beat each hook stands in for.

That is the full life of a view: it owns an element, renders into it, repaints idempotently when data changes, and tears itself down with one call. With that loop solid, the next foundations topics, templates and sync, are mostly about what goes inside render and where its data comes from.

Frequently Asked Questions

Does Backbone call render() automatically?

No. render is a convention, not a hook Backbone fires for you. You decide when to call it, usually once after creating the view and again whenever a model you are listening to changes, by binding this.listenTo(this.model, 'change', this.render).

How do I prevent duplicate event handlers after re-rendering?

Declare handlers in the events hash rather than binding them by hand. Backbone delegates those events on the view's root element, so they keep working across re-renders without stacking. Only if you replace the root element yourself do you need to call delegateEvents again.

What is the difference between el and $el?

el is the raw DOM node that the view manages. $el is the same node wrapped in jQuery, so you can call jQuery methods like $el.html() or $el.find(). Use el when you need the plain node and $el when you want jQuery convenience.

How do I properly destroy a Backbone view?

Call view.remove(). It detaches the element from the page and runs stopListening so no model keeps a reference to the gone view. If the view owns child views or plugins, override remove, clean those up, then call Backbone.View.prototype.remove on it.

Read next: Backbone.js Templates with Underscore, the next foundations guide, or revisit What is a Model? to see where a template's data comes from.

See the whole picture

Views are one piece. The complete guide shows how Models, Views, Routers, and Collections fit into one working application.

Explore the Backbone Guide →