The three stages
You declare. IndataSources on worker.customBlock(), you describe what your block needs: one or more named data sources, each with the properties it expects and their types.
src/index.ts
name and description are what a person sees when they configure the block, so write them for that reader. See the worker capability reference for every field.
Someone adds and binds. A user with access to the Worker can add an instance of the custom block on a page. Anyone with edit access to the page containing that instance can bind it to a Notion data source where they have at least viewer access. They map its properties to the ones you declared. For example, Ticket status can satisfy status.
Your frontend queries by key. At runtime the block asks for issues, not for a data source ID, and reads propertiesByKey.status, not a property ID. The keys you chose in the worker are the keys the frontend uses.
Access and permissions
The binding does not grant access to the data source. Every viewer must have access to each bound data source and its database. Access to the block’s page does not grant access to a separately bound database. Notion checks access, bindings, and schema before initialization. If a viewer lacks access to a required data source, the block does not load or render partial data. Give the viewer access or bind the block to a data source they can access. If a data source is unbound or its schema no longer matches the declaration, initialization fails with a binding error. If your component renders, its declared data sources are bound and match their declarations. Your code does not need to handle a half-configured state or check whether a declared data source exists. Viewer access to a bound data source does not grant edit access. A block can load successfully but still receive an access error when it writes. Handle these errors in your block code. See error handling.Prefer keys over IDs
Every row exposes its values twice:propertiesByKey, keyed by the keys you declared, and propertiesById, keyed by the bound data source’s real property IDs.
Prefer propertiesByKey. It is stable across every workspace your block is installed in, whereas property IDs belong to whichever data source someone happened to bind. Reach for propertiesById and propertyIdsByKey only when you need to work with properties beyond the ones you declared.
Declaring less is usually better
Every property you declare is a property someone must map before your block will run. A block that declares four properties is meaningfully easier to install than one that declares twelve. Declare what your block genuinely reads or writes. If a property is only used in one optional view, consider whether the block can degrade without it rather than making it a hard requirement of installation.Next
- Data sources reference — querying, updating rows, and the full result shape.
- Worker capability — every field of the declaration.
- Pages — creating and archiving rows, and working outside a bound data source.