diff --git a/lib/application.js b/lib/application.js
index 7a3abef5..7f35729a 100644
--- a/lib/application.js
+++ b/lib/application.js
@@ -10,6 +10,7 @@ var DataSource = require('loopback-datasource-juggler').DataSource
   , _ = require('underscore')
   , RemoteObjects = require('strong-remoting')
   , stringUtils = require('underscore.string')
+  , async = require('async')
   , path = require('path');
 
 /**
@@ -466,3 +467,58 @@ app.listen = function(cb) {
 
   return server;
 }
+
+/**
+ * **Do not call this method** if you are using `loopback-boot` to bootstrap your application.
+ * `loopback-boot` will call this method for you! Otherwise you must call `app.ready()` to run
+ * the `Model.ready()` hooks.
+ *
+ * Calling `ready()` will call `ready()` on all models attached to the `app`. Override
+ * the `ready()` method on a `Model` class to ensure you have access to a bootstrapped application.
+ *
+ * ```js
+ * module.exports = function(MyModel) {
+ *   MyModel.setup = function() {
+ *     // setup is called when a model is extended
+ *     // you must call `base.setup()` to extend the base class properly
+ *     this.base.setup();
+ * 
+ *     // add or remove remote methods and otherwise modify the `Model`
+ *     this.remoteMethod('myMethod');
+ *   }
+ * 
+ *   MyModel.beforeReady = function(app, cb) {
+ *     // async setup, runs after all models are `setup()`
+ *     // and before `ready()` is called
+ *     setTimeout(cb, 100);
+ *   }
+ * 
+ *   MyModel.ready = function(app) {
+ *     // MyModel and other classes can be used
+ *     // you should not modify any classes in this method
+ *     console.log(this.sharedClass.methods());
+ *   }
+ * }
+ * ```
+ */
+
+app.ready = function(cb) {
+  var app = this;
+  var models = app.models();
+  
+  async.each(models, function(Model, cb) {
+    Model.beforeReady(app, cb);
+  }, function(err) {
+    if(err) return done(err);
+
+    models.forEach(function(Model) {
+      Model.ready(app);
+    });
+
+    done();
+  });
+
+  function done(err) {
+    if(typeof cb === 'function') return cb(err);
+  }
+}
diff --git a/lib/models/model.js b/lib/models/model.js
index c9c48058..c5af88a4 100644
--- a/lib/models/model.js
+++ b/lib/models/model.js
@@ -694,6 +694,15 @@ Model.nestRemoting = function(relationName, options, cb) {
   }
 };
 
+Model.beforeReady = function(app, cb) {
+  // noop
+  cb();
+}
+
+Model.ready = function() {
+  // noop
+}
+
 // setup the initial model
 Model.setup();
 
diff --git a/test/app.test.js b/test/app.test.js
index 6d5b2937..7c0b0afd 100644
--- a/test/app.test.js
+++ b/test/app.test.js
@@ -350,4 +350,34 @@ describe('app', function() {
     var app = loopback();
     expect(app.loopback).to.equal(loopback);
   });
+
+  describe('app.ready()', function() {
+    it('should call the ready hooks', function(done) {
+      var app = loopback();
+      var called = 0;
+      var TestModel = app.model('TestModel', {}, {base: 'Model', dataSource: null});
+      TestModel.beforeReady = function(app, cb) {
+        called++;
+        cb();
+      }
+      TestModel.ready = function() {
+        called++;
+      };
+
+      app.ready(function() {
+        called++;
+      });
+
+      process.nextTick(function() {
+        expect(called).to.equal(3);
+        done();
+      });
+    });
+
+    it('should call built in methods if none provided', function(done) {
+      var app = loopback();
+      var TestModel = app.model('TestModel', {}, {base: 'Model', dataSource: null});
+      app.ready(done);
+    })
+  });
 });