diff --git a/script/component/DocumentPage.js b/script/component/DocumentPage.js
index 9086ec5..9041822 100644
--- a/script/component/DocumentPage.js
+++ b/script/component/DocumentPage.js
@@ -1,7 +1,7 @@
 const DocumentPage = {
     template: `
 <div class="document">
-    <markdown-reader :file="readUrl" :fragment="fragment"></markdown-reader>
+    <markdown-reader :file="readUrl" :hash="hash"></markdown-reader>
     
     <div class="contribute small">
         {{$t("contribute")}} <a :href="editUrl">{{$t("edit")}}</a>
@@ -11,7 +11,7 @@ const DocumentPage = {
     data: function() {
         return {
             document: this.$route.params.document,
-            fragment: this.$route.params.fragment,
+            hash: this.$route.hash,
             locale: $cookies.get("locale") || "en",
             readLink: "https://raw.githubusercontent.com/typeorm/typeorm/master/",
             editLink: "https://github.com/typeorm/typeorm/edit/master/"
@@ -20,7 +20,7 @@ const DocumentPage = {
     watch: {
         '$route': function(to, from) {
             this.document = to.params.document;
-            this.fragment = to.params.fragment;
+            this.hash = to.hash;
             this.updateTitle();
         }
     },
diff --git a/script/component/MarkdownReader.js b/script/component/MarkdownReader.js
index 50779d4..a85289a 100644
--- a/script/component/MarkdownReader.js
+++ b/script/component/MarkdownReader.js
@@ -1,6 +1,6 @@
 const MarkdownReader = {
     template: `<div v-html="html"></div>`,
-    props: ["file", "fragment"],
+    props: ["file", "hash"],
     data: function() {
         return {
             html: "",
@@ -12,27 +12,34 @@ const MarkdownReader = {
             this.setDocument();
             this.loadFile(file)
                 .then(() => {
-                    this.scrollToFragment(this.fragment);
+                    this.scrollToHash(this.hash);
                 });
         },
-        'fragment': function(fragment) {
-            this.scrollToFragment(fragment);
+        'hash': function(hash) {
+            this.scrollToHash(hash);
         }
     },
     created: function () {
         this.setDocument();
         this.loadFile(this.file)
             .then(() => {
-                this.scrollToFragment(this.fragment);
+                this.scrollToHash(this.hash);
             });
     },
     methods: {
-        scrollToFragment: function(fragment) {
-            const fragmentElement = document.getElementById(fragment);
-            if (fragmentElement)
-                fragmentElement.scrollIntoView();
-            else
+        scrollToHash: function(hash) {
+            if (!hash) {
                 window.scrollTo(0, 0);
+                return;
+            }
+
+            const hashElement = document.getElementById(hash.substr(1));
+            if (!hashElement){
+                window.scrollTo(0, 0);
+                return;
+            }
+
+            hashElement.scrollIntoView();
         },
         setDocument: function () {
             if(this.$route.params.document) {
@@ -51,7 +58,7 @@ const MarkdownReader = {
 
                     showdown.extension('header-anchors', () => {
 
-                        var ancTpl = '$1<a id="user-content-$3" class="anchor" href="#' + this.$route.params.document + '/$3" aria-hidden="true">#</a> $4';
+                        var ancTpl = '$1<a id="user-content-$3" class="anchor" href="#$3" aria-hidden="true">#</a> $4';
 
                         return [{
                             type: "html",
@@ -60,23 +67,7 @@ const MarkdownReader = {
                         }];
                     });
 
-                    showdown.extension('links-replacer', () => {
-                        return [{
-                            type: "html",
-                            regex: /<a href="#(.*)">/g,
-                            replace: "<a href='#/" + this.document + "/$1'>"
-                        }];
-                    });
-
-                    showdown.extension('other-page-links-replacer', () => {
-                        return [{
-                            type: "html",
-                            regex: /<a href="\.?\/?(docs\/)?(.*?)\.md\#?(.*?)">/g,
-                            replace: "<a href='#/$2/$3'>"
-                        }];
-                    });
-
-                    const converter = new showdown.Converter({ extensions: ['header-anchors', 'links-replacer', 'other-page-links-replacer'] });
+                    const converter = new showdown.Converter({ extensions: ['header-anchors'] });
                     converter.setFlavor('github');
                     converter.setOption('simpleLineBreaks', false);
 
diff --git a/script/index.js b/script/index.js
index 5eba223..dc6ccaf 100644
--- a/script/index.js
+++ b/script/index.js
@@ -9,16 +9,31 @@ const i18n = new VueI18n({
   locale: $cookies.get("locale") || "en", // set locale
   fallbackLocale: "en",
   messages // set locale messages
-})
+});
+
+const router = new VueRouter({
+  mode: "history",
+  routes: [{ path: "/:document?/:fragment?", component: DocumentPage }]
+});
+
+// Because the documentation previously used "hash" mode in the Router, paths
+// starting with a hash will be redirected to prevent breaking old permalinks.
+router.beforeEach((to, from, next) => {
+  if (to.fullPath.substr(0, 3) === "/#/") {
+    // Remove leading hash and replace following slash with hash.
+    // Before: https://typeorm.io/#/entities/entity-columns
+    // After:  https://typeorm.io/entities#entity-columns
+    const path = to.fullPath.substr(3).replace("/", "#");
+    next(path);
+    return;
+  }
+  next();
+});
 
 new Vue({
   el: "#app",
   i18n,
-  router: new VueRouter({
-    routes: [
-      { path: "/:document?/:fragment?", component: DocumentPage },
-    ]
-  }),
+  router: router,
   components: {
     "main-page": MainPage,
     "markdown-reader": MarkdownReader,