diff --git a/hn-server-fetch.js b/hn-server-fetch.js
new file mode 100644
index 0000000..3872e61
--- /dev/null
+++ b/hn-server-fetch.js
@@ -0,0 +1,100 @@
+require('isomorphic-fetch')
+
+/*
+The official Firebase API (https://github.com/HackerNews/API) requires multiple network
+connections to be made in order to fetch the list of Top Stories (indices) and then the
+summary content of these stories. Directly requesting these resources makes server-side
+rendering cumbersome as it is slow and ultimately requires that you maintain your own 
+cache to ensure full server renders are efficient. 
+
+To work around this problem, we can use one of the unofficial Hacker News APIs, specifically
+https://github.com/cheeaun/node-hnapi which directly returns the Top Stories and can cache 
+responses for 10 minutes. In ReactHN, we can use the unofficial API for a static server-side
+render and then 'hydrate' this once our components have mounted to display the real-time 
+experience. 
+
+The benefit of this is clients loading up the app that are on flakey networks (or lie-fi)
+can still get a fast render of content before the rest of our JavaScript bundle is loaded.
+ */
+
+/**
+ * Fetch top stories
+ */
+exports.fetchNews = function(page) {
+	page = page || ''
+	return fetch('http://node-hnapi.herokuapp.com/news' + page).then(function(response) {
+	  return response.json()
+	}).then(function(json) {
+	  var stories = '<ol class="Items__list" start="1">'
+	  json.forEach(function(data, index) {
+	      var story = '<li class="ListItem" style="margin-bottom: 16px;">' +
+	          '<div class="Item__title" style="font-size: 18px;"><a href="' + data.url + '">' + data.title + '</a> ' +
+	          '<span class="Item__host">(' + data.domain + ')</span></div>' +
+	          '<div class="Item__meta"><span class="Item__score">' + data.points + ' points</span> ' +
+	          '<span class="Item__by">by <a href="https://news.ycombinator.com/user?id=' + data.user + '">' + data.user + '</a></span> ' +
+	          '<time class="Item__time">' + data.time_ago + ' </time> | ' +
+	          '<a href="/news/story/' + data.id + '">' + data.comments_count + ' comments</a></div>'
+	      '</li>'
+	      stories += story
+	  })
+	  stories += '</ol>'
+	  return stories
+	})		
+}
+
+function renderNestedComment(data) {
+	return '<div class="Comment__kids">' +
+		        '<div class="Comment Comment--level1">' +
+		            '<div class="Comment__content">' +
+		                '<div class="Comment__meta"><span class="Comment__collapse" tabindex="0">[–]</span> ' +
+		                    '<a class="Comment__user" href="#/user/' + data.user + '">' + data.user + '</a> ' +
+		                    '<time>' + data.time_ago + '</time> ' +
+		                    '<a href="#/comment/' + data.id + '">link</a></div> ' +
+		                '<div class="Comment__text">' +
+		                    '<div>' + data.content +'</div> ' +
+		                    '<p><a href="https://news.ycombinator.com/reply?id=' + data.id + '">reply</a></p>' +
+		                '</div>' +
+		            '</div>' +
+		        '</div>' +
+		    '</div>'
+}
+
+function generateNestedCommentString(data) {
+	var output = ''
+	data.comments.forEach(function(comment) {
+		output+= renderNestedComment(comment)
+		if (comment.comments) {
+			output+= generateNestedCommentString(comment)
+		} 
+	})
+	return output
+}
+
+/**
+ * Fetch details of the story/post/item with (nested) comments
+ * TODO: Add article summary at top of nested comment thread
+ */
+exports.fetchItem = function(itemId) {
+	return fetch('https://node-hnapi.herokuapp.com/item/' + itemId).then(function(response) {
+		return response.json()
+	}).then(function(json) {
+		var comments = ''
+		json.comments.forEach(function(data, index) {
+			var comment = '<div class="Item__kids">' + 
+			'<div class="Comment Comment--level0">' +
+		    '<div class="Comment__content">' +
+		        '<div class="Comment__meta"><span class="Comment__collapse" tabindex="0">[–]</span> ' +
+		            '<a class="Comment__user" href="#/user/' + data.user + '">' + data.user + '</a> ' +
+		            '<time>' + data.time_ago + '</time> ' +
+		            '<a href="#/comment/' + data.id + '">link</a></div> ' +
+		        '<div class="Comment__text">' +
+		            '<div>' + data.content +'</div> ' + 
+		            '<p><a href="https://news.ycombinator.com/reply?id=' + data.id + '">reply</a></p>' +
+		        '</div>' +
+		    '</div>' +
+		   '</div>'
+			comments += generateNestedCommentString(data) + '</div>' + comment
+		})
+		return comments
+	})
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 3279d35..e918b28 100644
--- a/package.json
+++ b/package.json
@@ -24,11 +24,14 @@
   "main": "server.js",
   "dependencies": {
     "ejs": "^2.4.1",
+    "eslint-config-jonnybuchanan": "2.0.3",
     "events": "1.1.0",
     "express": "^4.13.4",
     "firebase": "2.4.2",
     "history": "2.1.1",
     "isomorphic-fetch": "^2.2.1",
+    "nwb": "0.8.1",
+    "object-assign": "^4.1.0",
     "react": "15.0.2",
     "react-dom": "15.0.2",
     "react-router": "2.4.0",
@@ -36,10 +39,8 @@
     "reactfire": "0.7.0",
     "scroll-behavior": "0.5.0",
     "setimmediate": "1.0.4",
-    "url-parse": "^1.1.1",
-    "eslint-config-jonnybuchanan": "2.0.3",
-    "nwb": "0.8.1",
     "sw-precache": "^3.1.1",
-    "sw-toolbox": "^3.1.1"
+    "sw-toolbox": "^3.1.1",
+    "url-parse": "^1.1.1"
   }
 }
diff --git a/server.js b/server.js
index dda4625..d163804 100644
--- a/server.js
+++ b/server.js
@@ -2,6 +2,8 @@ var express = require('express')
 var React = require('react')
 var renderToString = require('react-dom/server').renderToString
 var ReactRouter = require('react-router')
+var objectAssign = require('object-assign')
+var HNServerFetch = require('./hn-server-fetch')
 
 require('babel/register')
 var routes = require('./src/routes')
@@ -12,6 +14,47 @@ app.set('views', process.cwd() + '/src/views')
 app.set('port', (process.env.PORT || 5000))
 app.use(express.static('public'))
 
+
+app.get(['/', '/news'], function(req, res) {
+  ReactRouter.match({
+    routes: routes,
+    location: req.url
+  }, function(err, redirectLocation, props) {
+    if (err) {
+      res.status(500).send(err.message)
+    }
+    else if (redirectLocation) {
+      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
+    }
+    else if (props) {
+      HNServerFetch.fetchNews().then(function(stories) {
+        objectAssign(props.params, { prebootHTML: stories })
+        var markup = renderToString(React.createElement(ReactRouter.RouterContext, props, null))
+        res.render('index', { markup: markup })
+      })
+    }
+    else {
+      res.sendStatus(404)
+    }
+  })
+})
+
+app.get('/news/story/:id', function (req, res, next) {
+  var storyId = req.params.id
+  ReactRouter.match({
+    routes: routes,
+    location: req.url
+  }, function(err, redirectLocation, props) {
+    if (storyId) {
+      HNServerFetch.fetchItem(storyId).then(function(comments) {
+          objectAssign(props.params, { prebootHTML: comments })
+          var markup = renderToString(React.createElement(ReactRouter.RouterContext, props, null))
+          res.render('index', { markup: markup })
+      })
+    }
+  })  
+});
+
 app.get('*', function(req, res) {
   ReactRouter.match({
     routes: routes,
@@ -24,10 +67,8 @@ app.get('*', function(req, res) {
       res.redirect(302, redirectLocation.pathname + redirectLocation.search)
     }
     else if (props) {
-      var markup = renderToString(
-        React.createElement(ReactRouter.RouterContext, props, null)
-      )
-      res.render('index', { markup: markup })
+      var markup = renderToString(React.createElement(ReactRouter.RouterContext, props, null))
+      res.render('index', { markup: markup })        
     }
     else {
       res.sendStatus(404)
diff --git a/src/App.js b/src/App.js
index 15aaa7a..ea9e480 100644
--- a/src/App.js
+++ b/src/App.js
@@ -10,7 +10,9 @@ var SettingsStore = require('./stores/SettingsStore')
 var App = React.createClass({
   getInitialState() {
     return {
-      showSettings: false
+      showSettings: false,
+      showChildren: false,
+      prebootHTML: this.props.params.prebootHTML
     }
   },
 
@@ -22,6 +24,11 @@ var App = React.createClass({
     window.addEventListener('beforeunload', this.handleBeforeUnload)
   },
 
+  componentDidMount() {
+    // Empty the prebooted HTML and hydrate using live results from Firebase
+    this.setState({ prebootHTML: '', showChildren: true })
+  },
+
   componentWillUnmount() {
     if (typeof window === 'undefined') return
     window.removeEventListener('beforeunload', this.handleBeforeUnload)
@@ -58,7 +65,8 @@ var App = React.createClass({
         {this.state.showSettings && <Settings key="settings"/>}
       </div>
       <div className="App__content">
-        {this.props.children}
+        <div dangerouslySetInnerHTML={{ __html: this.state.prebootHTML }}/>
+        {this.state.showChildren ? this.props.children : ''}
       </div>
       <div className="App__footer">
         <a href="https://github.com/insin/react-hn">insin/react-hn</a>
diff --git a/src/Stories.js b/src/Stories.js
index c60d523..dcc5368 100644
--- a/src/Stories.js
+++ b/src/Stories.js
@@ -67,7 +67,7 @@ var Stories = React.createClass({
 
     // Display a list of placeholder items while we're waiting for the initial
     // list of story ids to load from Firebase.
-    if (this.state.stories.length === 0 && this.state.ids.length === 0) {
+    if (this.state.stories.length === 0 && this.state.ids.length === 0 && this.getPageNumber() > 0) {
       var dummyItems = []
       for (var i = page.startIndex; i < page.endIndex; i++) {
         dummyItems.push(
diff --git a/src/views/index.ejs b/src/views/index.ejs
index 202afd3..0bfda24 100644
--- a/src/views/index.ejs
+++ b/src/views/index.ejs
@@ -29,7 +29,7 @@
     <meta name="msapplication-TileColor" content="#222222">
     <meta name="msapplication-TileImage" content="img/mstile-144x144.png">
     <meta name="msapplication-config" content="img/browserconfig.xml">
-    
+    <base href="/">
     <link rel="stylesheet" href="css/style.css">
   </head>
   <body>