diff --git a/lib/core/note.dart b/lib/core/note.dart
index c9f5b90b..a1166c47 100644
--- a/lib/core/note.dart
+++ b/lib/core/note.dart
@@ -9,6 +9,9 @@ import 'package:gitjournal/utils/logger.dart';
 import 'package:gitjournal/utils/datetime.dart';
 
 import 'package:path/path.dart' as p;
+import 'package:meta/meta.dart';
+
+import 'package:markdown/markdown.dart' as md;
 
 import 'md_yaml_doc.dart';
 import 'md_yaml_doc_codec.dart';
@@ -366,6 +369,36 @@ class Note with NotesNotifier {
 
     return date.toString();
   }
+
+  Future<List<Link>> fetchLinks() async {
+    final doc = md.Document(
+      encodeHtml: false,
+      extensionSet: md.ExtensionSet.gitHubFlavored,
+    );
+
+    var lines = body.replaceAll('\r\n', '\n').split('\n');
+    var nodes = doc.parseLines(lines);
+    var possibleLinks = LinkExtractor().visit(nodes);
+
+    var links = <Link>[];
+    for (var l in possibleLinks) {
+      var path = l.filePath;
+      var isLocal = (path.startsWith('/') || path.startsWith('.')) &&
+          !path.contains('://');
+      if (isLocal) {
+        l.filePath = p.join(parent.folderPath, p.normalize(l.filePath));
+        links.add(l);
+      }
+    }
+
+    doc.linkReferences.forEach((key, value) {
+      print(value);
+      var filePath = value.destination;
+      links.add(Link(term: key, filePath: filePath));
+    });
+
+    return links;
+  }
 }
 
 String buildTitleFileName(String parentDir, String title) {
@@ -388,3 +421,59 @@ String buildTitleFileName(String parentDir, String title) {
     }
   }
 }
+
+class Link {
+  String term;
+  String filePath;
+
+  Link({@required this.term, @required this.filePath});
+
+  @override
+  int get hashCode => filePath.hashCode;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Note &&
+          runtimeType == other.runtimeType &&
+          filePath == other.filePath;
+}
+
+class LinkExtractor implements md.NodeVisitor {
+  List<Link> links = [];
+
+  @override
+  bool visitElementBefore(md.Element element) {
+    return true;
+  }
+
+  @override
+  void visitText(md.Text text) {}
+
+  @override
+  void visitElementAfter(md.Element el) {
+    final String tag = el.tag;
+
+    if (tag == 'a') {
+      var title = el.attributes['title'] ?? "";
+      if (title.isEmpty) {
+        for (var child in el.children) {
+          if (child is md.Text) {
+            title += child.text;
+          }
+        }
+      }
+
+      var url = el.attributes['href'];
+      var link = Link(term: title, filePath: url);
+      links.add(link);
+    }
+  }
+
+  List<Link> visit(List<md.Node> nodes) {
+    for (final node in nodes) {
+      node.accept(this);
+    }
+    return links;
+  }
+}
diff --git a/test/note_test.dart b/test/note_test.dart
index 0e5ab3f9..73e5d2b3 100644
--- a/test/note_test.dart
+++ b/test/note_test.dart
@@ -112,5 +112,32 @@ Hello""";
       var actualContent = File(notePath).readAsStringSync();
       expect(actualContent, equals(expectedContent));
     });
+
+    test('Should parse links', () async {
+      var content = """---
+title: Foo
+---
+
+[Hi](./foo.md)
+[Hi2](./po/../food.md)
+[Web](http://example.com)
+""";
+
+      var notePath = p.join(tempDir.path, "note6.md");
+      File(notePath).writeAsString(content);
+
+      var parentFolder = NotesFolderFS(null, tempDir.path);
+      var note = Note(parentFolder, notePath);
+      await note.load();
+
+      var links = await note.fetchLinks();
+      expect(links[0].filePath, p.join(tempDir.path, "foo.md"));
+      expect(links[0].term, "Hi");
+
+      expect(links[1].filePath, p.join(tempDir.path, "food.md"));
+      expect(links[1].term, "Hi2");
+
+      expect(links.length, 2);
+    });
   });
 }