Building a Fast Static Blog from Notion
This blog content is managed directly from @NotionHQ. Here is a high-level presentation of the flow for anyone wishing to accomplish something similar.
For a more “practical” guide, I recommend reading Jake’s blog post, which achieved something similar — but more advanced — for his own blog. Jake is also the publisher of the notion-api NPM library wrapper for interacting with Notion’s API.
The concept of creating and maintaining a website directly from Notion is not new.
There are many “Notion website generators”, with different approaches used over the years:
- The built-in “public” Notion pages (e.g. the Queue.so help center)
- “1st-gen” third-party website generators, extracting your website data via Notion public pages and “copying” them into your own custom domains (e.g. https://potion.so/ or https://notaku.so/)
- “2nd-gen” third-party website generators connecting to Notion via the new Notion API (e.g. https://feather.so/)
Pioneers of Notion-powered websites initially used the built-in feature of making pages available publicly. This was a super convenient method to deploy some content online in seconds: personal webpages, an online CV, an FAQ section, or a job description… For example, check out the Queue.so help center which is (currently) hosted on a Notion page.
The main limitation is that Notion does not support custom domains. So your website would have to live on a notion.so subdomain.
More advanced third-party solutions then decided to tackle this missing feature by generating and hosting websites on a custom domain after scrapping the information from your Notion public page. This is a paid but convenient, low-effort, no-code solution.
Finally, the idea of managing website content without leaving Notion jumped to the next level after Notion introduced its API. This allows developers to seamlessly connect to Notion databases without having to require some hand-made scrapping solutions.
This enables the more complex solutions to emerge, using the full power of Notion for content management, while allowing a lot of customization. A cool example is Feather.so which provides a very complete suite plugged on top of your Notion database.
The bottom line is that if you are in the market for an off-the-shelf solution, you have many options available today… but at the same time, it has never been easier to implement your own tailored solution and host it yourself.
Here are some ideas if you are willing to write some custom code.
1/ Set Up Notion as a CMS
Notion is great for writing notes and documentation. Therefore, it is inherently great as a CMS. Having everything in Notion makes it easier to just jump into writing and content management.
In the case of this blog, two databases were set up:
- One Notion database for blog articles: including a Publication Date field and Slug properties. The Summary and Social Image columns can be used for metadata and OpenGraph previews (Slack, Whatsapp…).
- Another database for static pages.
Each post is then written directly into Notion, including the text formatting, images (see further below), and even some more advanced blocks (e.g embed Youtube)
2/ Connect Notion to Next.js
In this case, we use Next.js and connect to the Notion API to retrieve the information about each page at build time:
This is done for each slug (in an un-optimized and redundant way, but acceptable because this is a build time).
This request will run for every “page” that we have in the Notion database. The list of pages is fetched from getStaticPaths.
3/ Export Static HTML
While hosting a server-side web application can make sense depending on your use case, static websites are very compelling options for blogs. Even if there are more and more options to speed up your server-side rendering, nothing can be faster than the pre-rendered static export.
- No server computation
- No call to Notion API at runtime
Also, static exports can be cached on the CDN (or your preferred hosting solution) and are generally cheaper to host.
For each type of block that we want to support, we can map some simple TSX equivalent for our HTML render.
3/ Support Images
The most tricky part of this endeavor is dealing with images:
- ❌ “Asset links” from the Notion API expire after 1 hour, so you can not rely on these URLs to host the images of your static website.
- ❌ “Next/Image” optimizations (e.g reducing the size, avoiding layout shifting…) are incompatible with static exports.
The solution used here is a 3-step process:
- Download images locally
4/ One-click Deployment
Using GitHub actions:← All Articles