jekyll-notion
Warning
The main branch is under active development for version 3. For the current stable release, please check out the v2.x.x branch.
Import Notion pages into Jekyll.
📚 Learn more with these guides:
Installation
Install via RubyGems:
gem install jekyll-notionOr add it to your Gemfile:
# Gemfile
gem 'jekyll-notion'Important
If you are using jekyll-archives, list jekyll-notion before
jekyll-archives in the Gemfile. Otherwise, imported pages will not
be picked up.
See the discussion
here.
Then enable the plugin in _config.yml:
plugins:
- jekyll-notionBeta version
Learn about the new changes in the following post.
If you want to try the beta release, install with the --pre flag:
gem install jekyll-notion --preOr pin the beta in your Gemfile:
gem "jekyll-notion", "3.0.0.beta1"⚠️ This version is under active development. For stable usage, prefer the latest 2.x.x release.
Usage
Before using the gem, create a Notion integration and generate a secret token.
Export the token as an environment variable:
export NOTION_TOKEN=<secret_...>Environment Variables
The plugin supports the following environment variables for configuration:
-
NOTION_TOKEN(required): Your Notion integration secret token -
JEKYLL_NOTION_CACHE: Fallback cache setting when not specified in_config.yml(1,true,yesto enable;0,false,noto disable) -
JEKYLL_NOTION_CACHE_DIR: Fallback cache directory when not specified in_config.yml(defaults to.cache/jekyll-notion/vcr_cassettes)
Example usage:
export NOTION_TOKEN=secret_abc123...
export JEKYLL_NOTION_CACHE=false
export JEKYLL_NOTION_CACHE_DIR=/tmp/my-custom-cacheDatabases
Share a Notion
database,
then specify its id in _config.yml:
notion:
databases:
- id: 5cfed4de3bdc4f43ae8ba653a7a2219bBy default, entries will be added to the posts collection.
You can also define multiple databases:
collections:
- recipes
- films
notion:
databases:
- id: b0e688e199af4295ae80b67eb52f2e2f
- id: 2190450d4cb34739a5c8340c4110fe21
collection: recipes
- id: e42383cd49754897b967ce453760499f
collection: filmsAfter running jekyll build or jekyll serve, the posts, recipes,
and films collections will contain pages from the specified databases.
Database options
Each database supports the following options:
-
id: the unique Notion database ID -
collection: which collection to assign pages to (postsby default) -
filter: a database filter -
sorts: database sorting criteria
notion:
databases:
- id: e42383cd49754897b967ce453760499f
collection: posts
filter: { "property": "Published", "checkbox": { "equals": true } }
sorts: [{ "timestamp": "created_time", "direction": "ascending" }]Post dates
By default, the Notion page created_time property sets the post
filename date. This value is used for Jekyll's date
variable`.
Since created_time cannot be modified, you can override it by adding a
custom Notion property named date (or Date). That property will be
used instead.
Pages
You can also load individual Notion pages:
notion:
pages:
- id: 5cfed4de3bdc4f43ae8ba653a7a2219bMultiple pages are supported:
notion:
pages:
- id: e42383cd49754897b967ce453760499f
- id: b0e688e199af4295ae80b67eb52f2e2f
- id: 2190450d4cb34739a5c8340c4110fe21The generated filename is based on the Notion page title (see Page filename).
All page properties are exposed as Jekyll front matter. For example, if
a page has a permalink property set to /about/, Jekyll will generate
/about/index.html.
Data
Instead of adding Notion pages to collections or pages, you can store
them under the Jekyll data object using the data option:
notion:
databases:
- id: b0e688e199af4295ae80b67eb52f2e2f
- id: e42383cd49754897b967ce453760499f
data: films
pages:
- id: e42383cd49754897b967ce453760499f
- id: b0e688e199af4295ae80b67eb52f2e2f
data: aboutEach page is stored as a hash. The page body is available under the
content key.
Example:
<ul>
{% for film in site.data.films %}
<li>{{ film.title }}</li>
{% endfor %}
</ul>
{{ site.data.about.content }}Other properties are mapped normally (see Notion properties).
Cache
All Notion requests are cached locally with the VCR gem to speed up rebuilds. The first build fetches from the Notion API; subsequent builds reuse the cache.
The cache mechanism provides:
- Per-page cache files that include the Notion page title + ID, making them easy to identify.
- Page-level deletion: remove a single cached page without affecting others.
- Databases fetched on every rebuild: new content in Notion is always discovered, while cached pages prevent unnecessary re-fetches.
Example cached file (title + ID):
.cache/jekyll-notion/vcr_cassettes/my-page-title-e42383cd49754897b967ce453760499f.ymlCache folder
Default: .cache/jekyll-notion/vcr_cassettes
You can override the cache directory in two ways:
Option 1: Configuration file (in _config.yml):
notion:
cache_dir: another/folderOption 2: Environment variable:
export JEKYLL_NOTION_CACHE_DIR=/path/to/custom/cacheThe _config.yml setting takes precedence over the environment variable.
Both relative and absolute paths are supported - relative paths are resolved
from the project root.
Cleaning the cache
- Delete the entire cache folder to reset everything.
- Or delete a single cached page file to refresh only that page.
Disabling the cache
To disable caching entirely:
notion:
cache: falseOr use the JEKYLL_NOTION_CACHE environment variable:
export JEKYLL_NOTION_CACHE=false # or 0, noSensitive data
The cache stores full request and response payloads from the Notion API. This may include sensitive information such as authentication tokens, URLs, or private content.
If you intend to store cached files in version control or share them with others, be mindful of what they contain.
By default, jekyll-notion automatically redacts the NOTION_TOKEN from all cache files.
If you need to mask additional values, you can configure VCR filters.
For example, add a file _plugins/vcr_config.rb:
VCR.configure do |config|
# Already handled by jekyll-notion: NOTION_TOKEN
# Example of masking a custom header or property:
config.filter_sensitive_data("[MASKED]") do |interaction|
interaction.request.headers["User-Agent"]&.first
end
endThis file will be automatically picked up by Jekyll and merged into the VCR configuration provided by jekyll-notion.
You can add filters for headers, query parameters, or any other values you don’t want exposed in the cache.
Notion properties
Notion page properties are mapped into each Jekyll document's front matter.
See the companion gem notion_to_md for details.
Page filename
Jekyll distinguishes between posts and other documents:
-
Posts: filenames follow the format
YEAR-MONTH-DAY-title.MARKUP, where the date comes from the Notioncreated_time(or thedateproperty if present). - Other documents: filenames are derived from the Notion page title.
Testing
Run the test suite:
bundle exec rspec # Run all tests
bundle exec rspec spec/path/to/test # Run specific test fileGolden Files
Tests use golden files to validate generated output against known-good snapshots. Update snapshots when expected output changes:
UPDATE_GOLDEN=1 bundle exec rspec