diff --git a/src/VectorConferenceHandler.js b/src/VectorConferenceHandler.js
index de1aa233..933f5993 100644
--- a/src/VectorConferenceHandler.js
+++ b/src/VectorConferenceHandler.js
@@ -53,7 +53,7 @@ ConferenceCall.prototype._joinConferenceUser = function() {
     // Make sure the conference user is in the group chat room
     var groupRoom = this.client.getRoom(this.groupRoomId);
     if (!groupRoom) {
-        return q.reject("Bad group room ID");
+        return Promise.reject("Bad group room ID");
     }
     var member = groupRoom.getMember(this.confUserId);
     if (member && member.membership === "join") {
diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js
index f4c369e0..4d08e833 100644
--- a/src/components/views/context_menus/RoomTileContextMenu.js
+++ b/src/components/views/context_menus/RoomTileContextMenu.js
@@ -61,7 +61,7 @@ module.exports = React.createClass({
         const roomId = this.props.room.roomId;
         var cli = MatrixClientPeg.get();
         if (!cli.isGuest()) {
-            q.delay(500).then(function() {
+            Promise.delay(500).then(function() {
                 if (tagNameOff !== null && tagNameOff !== undefined) {
                     cli.deleteRoomTag(roomId, tagNameOff).finally(function() {
                         // Close the context menu
@@ -212,7 +212,7 @@ module.exports = React.createClass({
         RoomNotifs.setRoomNotifsState(this.props.room.roomId, newState).done(() => {
             // delay slightly so that the user can see their state change
             // before closing the menu
-            return q.delay(500).then(() => {
+            return Promise.delay(500).then(() => {
                 if (this._unmounted) return;
                 // Close the context menu
                 if (this.props.onFinished) {
diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js
index 12f77ba7..e8ee5434 100644
--- a/src/components/views/settings/Notifications.js
+++ b/src/components/views/settings/Notifications.js
@@ -236,7 +236,7 @@ module.exports = React.createClass({
                 }
             }
 
-            q.all(deferreds).done(function() {
+            Promise.all(deferreds).done(function() {
                 self._refreshFromServer();
             }, function(error) {
                 var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@@ -306,7 +306,7 @@ module.exports = React.createClass({
             }
         }
 
-        q.all(deferreds).done(function(resps) {
+        Promise.all(deferreds).done(function(resps) {
             self._refreshFromServer();
         }, function(error) {
             var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@@ -361,7 +361,7 @@ module.exports = React.createClass({
         }
 
         // Then, add the new ones
-        q.all(removeDeferreds).done(function(resps) {
+        Promise.all(removeDeferreds).done(function(resps) {
             var deferreds = [];
 
             var pushRuleVectorStateKind = self.state.vectorContentRules.vectorState;
@@ -399,7 +399,7 @@ module.exports = React.createClass({
                 }
             }
 
-            q.all(deferreds).done(function(resps) {
+            Promise.all(deferreds).done(function(resps) {
                 self._refreshFromServer();
             }, onError);
         }, onError);
@@ -594,7 +594,7 @@ module.exports = React.createClass({
             self.setState({pushers: resp.pushers});
         });
 
-        q.all([pushRulesPromise, pushersPromise]).then(function() {
+        Promise.all([pushRulesPromise, pushersPromise]).then(function() {
             self.setState({
                 phase: self.phases.DISPLAY
             });
diff --git a/src/vector/index.js b/src/vector/index.js
index fa640c59..0cf8563f 100644
--- a/src/vector/index.js
+++ b/src/vector/index.js
@@ -188,7 +188,7 @@ var makeRegistrationUrl = function(params) {
 window.addEventListener('hashchange', onHashChange);
 
 function getConfig() {
-    let deferred = q.defer();
+    let deferred = Promise.defer();
 
     request(
         { method: "GET", url: "config.json" },
diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js
index 19187632..b88ee93f 100644
--- a/src/vector/platform/WebPlatform.js
+++ b/src/vector/platform/WebPlatform.js
@@ -68,7 +68,7 @@ export default class WebPlatform extends VectorBasePlatform {
         // annoyingly, the latest spec says this returns a
         // promise, but this is only supported in Chrome 46
         // and Firefox 47, so adapt the callback API.
-        const defer = q.defer();
+        const defer = Promise.defer();
         global.Notification.requestPermission((result) => {
             defer.resolve(result);
         });
@@ -103,7 +103,7 @@ export default class WebPlatform extends VectorBasePlatform {
     }
 
     _getVersion(): Promise<string> {
-        const deferred = q.defer();
+        const deferred = Promise.defer();
 
         // We add a cachebuster to the request to make sure that we know about
         // the most recent version on the origin server. That might not
diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js
index 04fe69f6..b66ec9ab 100644
--- a/src/vector/submit-rageshake.js
+++ b/src/vector/submit-rageshake.js
@@ -100,7 +100,7 @@ export default async function sendBugReport(bugReportEndpoint, opts) {
 }
 
 function _submitReport(endpoint, body, progressCallback) {
-    const deferred = q.defer();
+    const deferred = Promise.defer();
 
     const req = new XMLHttpRequest();
     req.open("POST", endpoint);
diff --git a/test/app-tests/joining.js b/test/app-tests/joining.js
index 6788b534..34acd26a 100644
--- a/test/app-tests/joining.js
+++ b/test/app-tests/joining.js
@@ -118,7 +118,7 @@ describe('joining a room', function () {
                 // wait for the directory requests
                 httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []});
                 httpBackend.when('GET', '/thirdparty/protocols').respond(200, {});
-                return q.all([
+                return Promise.all([
                     httpBackend.flush('/thirdparty/protocols'),
                     httpBackend.flush('/publicRooms'),
                 ]);
@@ -139,14 +139,14 @@ describe('joining a room', function () {
                 httpBackend.when('GET', '/rooms/'+encodeURIComponent(ROOM_ID)+"/initialSync")
                     .respond(401, {errcode: 'M_GUEST_ACCESS_FORBIDDEN'});
 
-                return q.all([
+                return Promise.all([
                     httpBackend.flush('/directory/room/'+encodeURIComponent(ROOM_ALIAS), 1, 200),
                     httpBackend.flush('/rooms/'+encodeURIComponent(ROOM_ID)+"/initialSync", 1, 200),
                 ]);
             }).then(() => {
                 httpBackend.verifyNoOutstandingExpectation();
 
-                return q.delay(1);
+                return Promise.delay(1);
             }).then(() => {
                 // we should now have a roomview, with a preview bar
                 roomView = ReactTestUtils.findRenderedComponentWithType(
@@ -164,14 +164,14 @@ describe('joining a room', function () {
                     .respond(200, {room_id: ROOM_ID});
             }).then(() => {
                 // wait for the join request to be made
-                return q.delay(1);
+                return Promise.delay(1);
             }).then(() => {
                 // and again, because the state update has to go to the store and
                 // then one dispatch within the store, then to the view
                 // XXX: This is *super flaky*: a better way would be to declare
                 // that we expect a certain state transition to happen, then wait
                 // for that transition to occur.
-                return q.delay(1);
+                return Promise.delay(1);
             }).then(() => {
                 // the roomview should now be loading
                 expect(roomView.state.room).toBe(null);
@@ -186,7 +186,7 @@ describe('joining a room', function () {
             }).then(() => {
                 httpBackend.verifyNoOutstandingExpectation();
 
-                return q.delay(1);
+                return Promise.delay(1);
             }).then(() => {
                 // We've joined, expect this to false
                 expect(roomView.state.joining).toBe(false);
diff --git a/test/app-tests/loading.js b/test/app-tests/loading.js
index e3291b0b..558cbc5e 100644
--- a/test/app-tests/loading.js
+++ b/test/app-tests/loading.js
@@ -103,7 +103,7 @@ describe('loading:', function () {
             toString: function() { return this.search + this.hash; },
         };
 
-        let tokenLoginCompleteDefer = q.defer();
+        let tokenLoginCompleteDefer = Promise.defer();
         tokenLoginCompletePromise = tokenLoginCompleteDefer.promise;
 
         function onNewScreen(screen) {
@@ -171,7 +171,7 @@ describe('loading:', function () {
         it('gives a login panel by default', function (done) {
             loadApp();
 
-            q.delay(1).then(() => {
+            Promise.delay(1).then(() => {
                 // at this point, we're trying to do a guest registration;
                 // we expect a spinner
                 assertAtLoadingSpinner(matrixChat);
@@ -183,7 +183,7 @@ describe('loading:', function () {
                 return httpBackend.flush();
             }).then(() => {
                 // Wait for another trip around the event loop for the UI to update
-                return q.delay(10);
+                return Promise.delay(10);
             }).then(() => {
                 // we expect a single <Login> component following session load
                 ReactTestUtils.findRenderedComponentWithType(
@@ -197,7 +197,7 @@ describe('loading:', function () {
                 uriFragment: "#/room/!room:id",
             });
 
-            q.delay(1).then(() => {
+            Promise.delay(1).then(() => {
                 // at this point, we're trying to do a guest registration;
                 // we expect a spinner
                 assertAtLoadingSpinner(matrixChat);
@@ -209,7 +209,7 @@ describe('loading:', function () {
                 return httpBackend.flush();
             }).then(() => {
                 // Wait for another trip around the event loop for the UI to update
-                return q.delay(10);
+                return Promise.delay(10);
             }).then(() => {
                 return completeLogin(matrixChat);
             }).then(() => {
@@ -232,7 +232,7 @@ describe('loading:', function () {
                 uriFragment: "#/login",
             });
 
-            return q.delay(100).then(() => {
+            return Promise.delay(100).then(() => {
                 // we expect a single <Login> component
                 ReactTestUtils.findRenderedComponentWithType(
                     matrixChat, sdk.getComponent('structures.login.Login'));
@@ -339,7 +339,7 @@ describe('loading:', function () {
                 },
             });
 
-            return q.delay(1).then(() => {
+            return Promise.delay(1).then(() => {
                 // we expect a loading spinner while we log into the RTS
                 assertAtLoadingSpinner(matrixChat);
 
@@ -366,7 +366,7 @@ describe('loading:', function () {
                 });
 
                 // give the UI a chance to display
-                return q.delay(50);
+                return Promise.delay(50);
             });
 
             it('shows a login view', function() {
@@ -403,7 +403,7 @@ describe('loading:', function () {
         it('shows a home page by default', function (done) {
             loadApp();
 
-            q.delay(1).then(() => {
+            Promise.delay(1).then(() => {
                 // at this point, we're trying to do a guest registration;
                 // we expect a spinner
                 assertAtLoadingSpinner(matrixChat);
@@ -436,7 +436,7 @@ describe('loading:', function () {
 
             loadApp();
 
-            q.delay(1).then(() => {
+            Promise.delay(1).then(() => {
                 // at this point, we're trying to do a guest registration;
                 // we expect a spinner
                 assertAtLoadingSpinner(matrixChat);
@@ -471,7 +471,7 @@ describe('loading:', function () {
             loadApp({
                 uriFragment: "#/room/!room:id"
             });
-            q.delay(1).then(() => {
+            Promise.delay(1).then(() => {
                 // at this point, we're trying to do a guest registration;
                 // we expect a spinner
                 assertAtLoadingSpinner(matrixChat);
@@ -530,7 +530,7 @@ describe('loading:', function () {
 
                     dis.dispatch({ action: 'start_login' });
 
-                    return q.delay(1);
+                    return Promise.delay(1);
                 });
             });
 
@@ -559,7 +559,7 @@ describe('loading:', function () {
 
                 ReactTestUtils.Simulate.click(returnToApp);
 
-                return q.delay(1).then(() => {
+                return Promise.delay(1).then(() => {
                     // we should be straight back into the home page
                     ReactTestUtils.findRenderedComponentWithType(
                         matrixChat, sdk.getComponent('structures.HomePage'));
@@ -574,7 +574,7 @@ describe('loading:', function () {
                 queryString: "?loginToken=secretToken&homeserver=https%3A%2F%2Fhomeserver&identityServer=https%3A%2F%2Fidserver",
             });
 
-            q.delay(1).then(() => {
+            Promise.delay(1).then(() => {
                 // we expect a spinner while we're logging in
                 assertAtLoadingSpinner(matrixChat);
 
@@ -629,7 +629,7 @@ describe('loading:', function () {
 
         return httpBackend.flush().then(() => {
             // Wait for another trip around the event loop for the UI to update
-            return q.delay(1);
+            return Promise.delay(1);
         }).then(() => {
             // we expect a spinner
             ReactTestUtils.findRenderedComponentWithType(
@@ -674,7 +674,7 @@ function awaitSyncingSpinner(matrixChat, retryLimit, retryCount) {
         }
         // loading can take quite a long time, because we delete the
         // indexedDB store.
-        return q.delay(5).then(() => {
+        return Promise.delay(5).then(() => {
             return awaitSyncingSpinner(matrixChat, retryLimit, retryCount + 1);
         });
     }
@@ -711,7 +711,7 @@ function awaitRoomView(matrixChat, retryLimit, retryCount) {
             throw new Error("MatrixChat still not ready after " +
                             retryCount + " tries");
         }
-        return q.delay(0).then(() => {
+        return Promise.delay(0).then(() => {
             return awaitRoomView(matrixChat, retryLimit, retryCount + 1);
         });
     }