Live demo · Notion + ChalkSQL

Your Notion workspace,
as SQL tables.

Roadmaps, account lists and request trackers live in Notion. ChalkSQL reads each Notion database as a table, turns your WHERE clause into a Notion filter, and joins what comes back with your warehouse in the same query.

Run SQL against a Notion workspace

Pick a query or write your own, then press Run query. On the right is every request ChalkSQL sent to Notion, with the filter it pushed down and how many pages came back.

ChalkSQL

Filter and aggregate one Notion database. The IN list and the ARR threshold both become a Notion filter, so only matching pages come back.

What Notion received

Run a query to see the requests.

Result

Results appear here.

The workspace belongs to Fernhill, a fictional analytics company. Its roadmap, accounts and feature requests are served by a stand-in for Notion's REST API (database queries, filters, cursor pagination and search), so the exact requests are visible. The connector does not depend on the stand-in: point it at api.notion.com with an integration token and it reads a real workspace. ChalkSQL and the connector run live on a Chalk scaling group.

How it works

Notion is a schema provider in ChalkSQL's catalog, next to your warehouse, your databases and your vector indexes. Queries over it get the same optimizer as everything else.

Databases become tables

Register a Notion integration and each database it can see is a ChalkSQL table: title, text, select and status become strings, numbers become doubles, dates become dates, and people, multi-select and relations become lists.

WHERE becomes a Notion filter

Before the scan runs, the optimizer offers it the query's predicates. The ones Notion can evaluate turn into a filter object on the database query, so Notion only sends back the pages you asked for.

SQL does the rest

Joins, aggregates, window functions and anything Notion cannot evaluate run in ChalkSQL, across Notion and every other source in the same query. Results stream in a page at a time by following Notion's cursors.

Getting started

A Notion source in one catalog call

The connector is a ChalkSQL schema provider. Each Notion database it is given becomes a table, discovered from the database's schema, and each scan is a pushdown-capable batch function that pages through Notion's query API.

Register it once and Notion is queryable from anywhere ChalkSQL runs, joined with anything else in the catalog.

-- Notion databases are tables; their properties are typed columns.
SELECT a.account, a.arr, u.weekly_active_users
FROM notion.accounts a
JOIN warehouse.product_usage u ON u.domain = a.domain
WHERE a.tier = 'Enterprise'        -- runs in Notion
  AND a.arr >= 250000              -- runs in Notion
  AND u.weekly_active_users < 50   -- runs in ChalkSQL
ORDER BY a.arr DESC

What runs in Notion

The connector only pushes a predicate when Notion can answer it. Everything else stays in ChalkSQL, so a query returns the same rows whether or not it was pushed.

Numbers and dates

=, <>, <, <=, > and >= against a literal become Notion's number and date conditions, like greater_than or on_or_before. Exact, so ChalkSQL drops them.

Selects and statuses

= and <> become equals and does_not_equal, and an IN list becomes an or of equals. Exact.

Text

= and LIKE 'x%', '%x' or '%x%' become equals, starts_with, ends_with and contains. Notion compares text case-insensitively, so these narrow the scan and ChalkSQL re-checks every row.

Lists

contains(tags, 'ml') on a multi-select or relation becomes Notion's contains. IS NULL and IS NOT NULL become is_empty and is_not_empty on any property.

AND and OR

Combined into Notion's compound and / or filters. If only part of an AND can be pushed, that part still narrows the scan.

LIMIT

A LIMIT with no ORDER BY becomes the request's page_size, and the scan stops once it has enough rows.

Query the tools your team already uses

Notion, your warehouse, your databases and your vector indexes in one SQL query. Talk to an engineer about the sources you want to join.