diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 550c10dba3eb2f08c64ddee64eb9a326838da295..c3c7f4c2b9b030a49d89e27200df443c19c06220 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -137,7 +137,9 @@ window.FileList={
 
 		var download_url = null;
 		if (!param.download_url) {
-			download_url = OC.Router.generate('download', { file: $('#dir').val()+'/'+name });
+			download_url = OC.generateUrl(
+				'/download{file}',
+				{ file: $('#dir').val()+'/'+name });
 		} else {
 			download_url = param.download_url;
 		}
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index f4546120702129e7879b3134d234f6c0dca3afd5..c93862e85d8e0c8a9b83427e48125bd3bd96005e 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -780,9 +780,9 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
 
 		if ( $('#isPublic').length ) {
 			urlSpec.t = $('#dirToken').val();
-			previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec);
+			previewURL = OC.generateUrl('/publicpreview.png?') + $.param(urlSpec);
 		} else {
-			previewURL = OC.Router.generate('core_ajax_preview', urlSpec);
+			previewURL = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
 		}
 		previewURL = previewURL.replace('(', '%28');
 		previewURL = previewURL.replace(')', '%29');
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index 3469829b6f7dbc72bb34642edda9b8485ece5089..9417a6eeb899c2a96224ac879027c5590ee8acbc 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -1,4 +1,5 @@
 <?php
+/** @var $this OC_Router */
 $this->create('core_ajax_public_preview', '/publicpreview.png')->action(
 function() {
 	require_once __DIR__ . '/../ajax/publicpreview.php';
diff --git a/core/js/jquery.avatar.js b/core/js/jquery.avatar.js
index 02a40c088b4f46866f0a448cdecb2b2aac69bb6e..381c42d9dbb5f816c0e0b8de992d481a603e72ce 100644
--- a/core/js/jquery.avatar.js
+++ b/core/js/jquery.avatar.js
@@ -75,31 +75,32 @@
 
 		var $div = this;
 
-		OC.Router.registerLoadedCallback(function() {
-			var url = OC.Router.generate('core_avatar_get', {user: user, size: size})+'?requesttoken='+oc_requesttoken;
-			$.get(url, function(result) {
-				if (typeof(result) === 'object') {
-					if (!hidedefault) {
-						if (result.data && result.data.displayname) {
-							$div.imageplaceholder(user, result.data.displayname);
-						} else {
-							$div.imageplaceholder(user);
-						}
+		var url = OC.generateUrl(
+			'/avatar/{user}/{size}?requesttoken={requesttoken}',
+			{user: user, size: size, requesttoken: oc_requesttoken});
+
+		$.get(url, function(result) {
+			if (typeof(result) === 'object') {
+				if (!hidedefault) {
+					if (result.data && result.data.displayname) {
+						$div.imageplaceholder(user, result.data.displayname);
 					} else {
-						$div.hide();
+						$div.imageplaceholder(user);
 					}
 				} else {
-					$div.show();
-					if (ie8fix === true) {
-						$div.html('<img src="'+url+'#'+Math.floor(Math.random()*1000)+'">');
-					} else {
-						$div.html('<img src="'+url+'">');
-					}
+					$div.hide();
 				}
-				if(typeof callback === 'function') {
-					callback();
+			} else {
+				$div.show();
+				if (ie8fix === true) {
+					$div.html('<img src="'+url+'#'+Math.floor(Math.random()*1000)+'">');
+				} else {
+					$div.html('<img src="'+url+'">');
 				}
-			});
+			}
+			if(typeof callback === 'function') {
+				callback();
+			}
 		});
 	};
 }(jQuery));
diff --git a/core/js/js.js b/core/js/js.js
index 21ccee0f1d54b6fc3af37d68bcc928aec75a1d16..80d83dc07f9b25e3ff55e517f522f15fff426bd8 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -194,6 +194,27 @@ var OC={
 	linkToRemoteBase:function(service) {
 		return OC.webroot + '/remote.php/' + service;
 	},
+
+	generateUrl: function(url, params) {
+		var _build = function (text, vars) {
+			return text.replace(/{([^{}]*)}/g,
+				function (a, b) {
+					var r = vars[b];
+					return typeof r === 'string' || typeof r === 'number' ? r : a;
+				}
+			);
+		};
+		if (url.charAt(0) !== '/') {
+			url = '/' + url;
+
+		}
+		return OC.webroot + '/index.php' + _build(url, params);
+	},
+
+	linkToRoute:function(route) {
+		return OC.webroot + '/index.php/' + route;
+	},
+
 	/**
 	 * @brief Creates an absolute url for remote use
 	 * @param string $service id
@@ -791,12 +812,10 @@ function initCore() {
 		if (interval < 60) {
 			interval = 60;
 		}
-		OC.Router.registerLoadedCallback(function(){
-			var url = OC.Router.generate('heartbeat');
-			setInterval(function(){
-				$.post(url);
-			}, interval * 1000);
-		});
+		var url = OC.linkToRoute('heartbeat');
+		setInterval(function(){
+			$.post(url);
+		}, interval * 1000);
 	}
 
 	// session heartbeat (defaults to enabled)
diff --git a/core/js/router.js b/core/js/router.js
deleted file mode 100644
index e6ef54a1864e037b0660b30ba1115b6697eaa8d0..0000000000000000000000000000000000000000
--- a/core/js/router.js
+++ /dev/null
@@ -1,81 +0,0 @@
-OC.router_base_url = OC.webroot + '/index.php';
-OC.Router = {
-	// register your ajax requests to load after the loading of the routes
-	// has finished. otherwise you face problems with race conditions
-	registerLoadedCallback: function(callback){
-		if (!this.routes_request){
-			return;
-		}
-		this.routes_request.done(callback);
-	},
-	routes_request: !window.TESTING && $.ajax(OC.router_base_url + '/core/routes.json', {
-		dataType: 'json',
-		success: function(jsondata) {
-			if (jsondata.status === 'success') {
-				OC.Router.routes = jsondata.data;
-			}
-		}
-	}),
-	generate:function(name, opt_params) {
-		if (!('routes' in this)) {
-			if(this.routes_request.state() != 'resolved') {
-				console.warn('To avoid race conditions, please register a callback');// wait
-			}
-		}
-		if (!(name in this.routes)) {
-			throw new Error('The route "' + name + '" does not exist.');
-		}
-		var route = this.routes[name];
-		var params = opt_params || {};
-		var unusedParams = $.extend(true, {}, params);
-		var url = '';
-		var optional = true;
-		$(route.tokens).each(function(i, token) {
-			if ('text' === token[0]) {
-			    url = token[1] + url;
-			    optional = false;
-
-			    return;
-			}
-
-			if ('variable' === token[0]) {
-			    if (false === optional || !(token[3] in route.defaults)
-				    || ((token[3] in params) && params[token[3]] != route.defaults[token[3]])) {
-				var value;
-				if (token[3] in params) {
-				    value = params[token[3]];
-				    delete unusedParams[token[3]];
-				} else if (token[3] in route.defaults) {
-				    value = route.defaults[token[3]];
-				} else if (optional) {
-				    return;
-				} else {
-				    throw new Error('The route "' + name + '" requires the parameter "' + token[3] + '".');
-				}
-
-				var empty = true === value || false === value || '' === value;
-
-				if (!empty || !optional) {
-				    url = token[1] + encodeURIComponent(value).replace(/%2F/g, '/') + url;
-				}
-
-				optional = false;
-			    }
-
-			    return;
-			}
-
-			throw new Error('The token type "' + token[0] + '" is not supported.');
-		});
-		if (url === '') {
-			url = '/';
-		}
-
-		unusedParams = $.param(unusedParams);
-		if (unusedParams.length > 0) {
-			url += '?'+unusedParams;
-		}
-
-		return OC.router_base_url + url;
-	}
-}
diff --git a/core/js/tags.js b/core/js/tags.js
index bc6d7b4e0710936ea7a560d9ee7dcc8506c99876..bc2b42bf5ff58f4dbbf5c102c7a6ecc602ec87e4 100644
--- a/core/js/tags.js
+++ b/core/js/tags.js
@@ -69,7 +69,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_ids_for_tag', {type: type});
+			url = OC.generateUrl('/tags/{type}/ids', {type: type});
 		$.getJSON(url, {tag: tag}, function(response) {
 			if(response.status === 'success') {
 				defer.resolve(response.ids);
@@ -90,7 +90,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_favorites', {type: type});
+			url = OC.generateUrl('/tags/{type}/favorites', {type: type});
 		$.getJSON(url, function(response) {
 			if(response.status === 'success') {
 				defer.resolve(response.ids);
@@ -111,7 +111,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_tags', {type: type});
+			url = OC.generateUrl('/tags/{type}', {type: type});
 		$.getJSON(url, function(response) {
 			if(response.status === 'success') {
 				defer.resolve(response.tags);
@@ -133,7 +133,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_tag', {type: type, id: id});
+			url = OC.generateUrl('/tags/{type}/tag/{id}/', {type: type, id: id});
 		$.post(url, {tag: tag}, function(response) {
 			if(response.status === 'success') {
 				defer.resolve(response);
@@ -157,7 +157,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_untag', {type: type, id: id});
+			url = OC.generateUrl('/tags/{type}/untag/{id}/', {type: type, id: id});
 		$.post(url, {tag: tag}, function(response) {
 			if(response.status === 'success') {
 				defer.resolve(response);
@@ -181,7 +181,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_favorite', {type: type, id: id});
+			url = OC.generateUrl('/tags/{type}/favorite/{id}/', {type: type, id: id});
 		$.post(url, function(response) {
 			if(response.status === 'success') {
 				defer.resolve(response);
@@ -205,7 +205,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_unfavorite', {type: type, id: id});
+			url = OC.generateUrl('/tags/{type}/unfavorite/{id}/', {type: type, id: id});
 		$.post(url, function(response) {
 			if(response.status === 'success') {
 				defer.resolve();
@@ -229,7 +229,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_add', {type: type});
+			url = OC.generateUrl('/tags/{type}/add', {type: type});
 		$.post(url,{tag:tag}, function(response) {
 			if(typeof cb == 'function') {
 				cb(response);
@@ -256,7 +256,7 @@ OC.Tags= {
 		type = type ? type : this.type;
 		var defer = $.Deferred(),
 			self = this,
-			url = OC.Router.generate('core_tags_delete', {type: type});
+			url = OC.generateUrl('/tags/{type}/delete', {type: type});
 		if(!tags || !tags.length) {
 			throw new Error(t('core', 'No tags selected for deletion.'));
 		}
diff --git a/core/routes.php b/core/routes.php
index aea788bdc6b1788c0262601c0698dc8534aa4ec7..76cf03c36733404d6b2d32c7a4c0db559ad0047b 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -65,8 +65,6 @@ $this->create('core_tags_delete', '/tags/{type}/delete')
 $this->create('js_config', '/core/js/oc.js')
 	->actionInclude('core/js/config.php');
 // Routing
-$this->create('core_ajax_routes', '/core/routes.json')
-	->action('OC_Router', 'JSRoutes');
 $this->create('core_ajax_preview', '/core/preview.png')
 	->actionInclude('core/ajax/preview.php');
 $this->create('core_lostpassword_index', '/lostpassword/')
diff --git a/lib/base.php b/lib/base.php
index 49cbb1279d11acfb77d5a04278a8304253b8d136..7703e83ec2ef5bdaabd209865e74c216299cec84 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -316,7 +316,6 @@ class OC {
 		OC_Util::addScript("config");
 		//OC_Util::addScript( "multiselect" );
 		OC_Util::addScript('search', 'result');
-		OC_Util::addScript('router');
 		OC_Util::addScript("oc-requesttoken");
 
 		// avatars
diff --git a/lib/private/router.php b/lib/private/router.php
index 19c1e4473ecaeccc560ca46df5212292dd779a4c..918e3b13206d3236ff04b624158089aa299217ed 100644
--- a/lib/private/router.php
+++ b/lib/private/router.php
@@ -158,28 +158,4 @@ class OC_Router {
 		return $this->getGenerator()->generate($name, $parameters, $absolute);
 	}
 
-	/**
-	 * Generate JSON response for routing in javascript
-	 */
-	public static function JSRoutes()
-	{
-		$router = OC::getRouter();
-
-		$etag = $router->getCacheKey();
-		OC_Response::enableCaching();
-		OC_Response::setETagHeader($etag);
-
-		$root = $router->getCollection('root');
-		$routes = array();
-		foreach($root->all() as $name => $route) {
-			$compiled_route = $route->compile();
-			$defaults = $route->getDefaults();
-			unset($defaults['action']);
-			$routes[$name] = array(
-				'tokens' => $compiled_route->getTokens(),
-				'defaults' => $defaults,
-			);
-		}
-		OCP\JSON::success ( array( 'data' => $routes ) );
-	}
 }
diff --git a/settings/js/admin.js b/settings/js/admin.js
index 5ea6a5af2df2db8980c7039bab6a3dbbb2a7b1c8..cfb1cb788d058f5f506ec56b6f42d715a0f36c7c 100644
--- a/settings/js/admin.js
+++ b/settings/js/admin.js
@@ -64,7 +64,7 @@ $(document).ready(function(){
 	$('#mail_settings').change(function(){
 		OC.msg.startSaving('#mail_settings .msg');
 		var post = $( "#mail_settings" ).serialize();
-		$.post(OC.Router.generate('settings_mail_settings'), post, function(data){
+		$.post(OC.generateUrl('/settings/admin/mailsettings'), post, function(data){
 			OC.msg.finishedSaving('#mail_settings .msg', data);
 		});
 	});
diff --git a/settings/js/personal.js b/settings/js/personal.js
index 98bfe7132d488014ee2583a855edf5370ed6347e..7a4257f1c973002aea90eb2815383b3003f45a25 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -67,7 +67,7 @@ function showAvatarCropper() {
 	$cropper.prepend("<img>");
 	$cropperImage = $('#cropper img');
 
-	$cropperImage.attr('src', OC.Router.generate('core_avatar_get_tmp')+'?requesttoken='+oc_requesttoken+'#'+Math.floor(Math.random()*1000));
+	$cropperImage.attr('src', OC.generateUrl('/avatar/tmp')+'?requesttoken='+oc_requesttoken+'#'+Math.floor(Math.random()*1000));
 
 	// Looks weird, but on('load', ...) doesn't work in IE8
 	$cropperImage.ready(function(){
@@ -95,7 +95,7 @@ function sendCropData() {
 		w: cropperdata.w,
 		h: cropperdata.h
 	};
-	$.post(OC.Router.generate('core_avatar_post_cropped'), {crop: data}, avatarResponseHandler);
+	$.post(OC.generateUrl('/avatar/cropped'), {crop: data}, avatarResponseHandler);
 }
 
 function saveCoords(c) {
@@ -132,7 +132,7 @@ $(document).ready(function(){
 			$('#passwordchanged').hide();
 			$('#passworderror').hide();
 			// Ajax foo
-			$.post(OC.Router.generate('settings_personal_changepassword'), post, function(data){
+			$.post(OC.generateUrl('/settings/personal/changepassword'), post, function(data){
 				if( data.status === "success" ){
 					$('#pass1').val('');
 					$('#pass2').val('');
@@ -243,7 +243,7 @@ $(document).ready(function(){
 		OC.dialogs.filepicker(
 			t('settings', "Select a profile picture"),
 			function(path){
-				$.post(OC.Router.generate('core_avatar_post'), {path: path}, avatarResponseHandler);
+				$.post(OC.generateUrl('/avatar/'), {path: path}, avatarResponseHandler);
 			},
 			false,
 			["image/png", "image/jpeg"]
@@ -253,7 +253,7 @@ $(document).ready(function(){
 	$('#removeavatar').click(function(){
 		$.ajax({
 			type:	'DELETE',
-			url:	OC.Router.generate('core_avatar_delete'),
+			url:	OC.generateUrl('/avatar/'),
 			success: function(msg) {
 				updateAvatar(true);
 			}
diff --git a/settings/js/users.js b/settings/js/users.js
index 160d0a8d9d2891a68614824964299d01d2183e9a..6b5447c767438168356f225e2d1f7fad3af80d58 100644
--- a/settings/js/users.js
+++ b/settings/js/users.js
@@ -225,7 +225,8 @@ var UserList = {
 		}
 		$('table+.loading').css('visibility', 'visible');
 		UserList.updating = true;
-		$.get(OC.Router.generate('settings_ajax_userlist', { offset: UserList.offset, limit: UserList.usersToLoad }), function (result) {
+		var query = $.param({ offset: UserList.offset, limit: UserList.usersToLoad });
+		$.get(OC.generateUrl('/settings/ajax/userlist') + query, function (result) {
 			var loadedUsers = 0;
 			var trs = [];
 			if (result.status === 'success') {
@@ -401,7 +402,7 @@ $(document).ready(function () {
 				if ($(this).val().length > 0) {
 					var recoveryPasswordVal = $('input:password[id="recoveryPassword"]').val();
 					$.post(
-						OC.Router.generate('settings_users_changepassword'),
+						OC.generateUrl('/settings/users/changepassword'),
 						{username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal},
 						function (result) {
 							if (result.status != 'success') {
diff --git a/settings/routes.php b/settings/routes.php
index 64f7122f0cf6492cbe0365e386f574df80ff4279..7d94f130088e0c2b1964e90ecf526059b083b9f6 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -6,6 +6,8 @@
  * See the COPYING-README file.
  */
 
+/** @var $this OC_Router */
+
 // Settings pages
 $this->create('settings_help', '/settings/help')
 	->actionInclude('settings/help.php');