Check out our Plugin community sub-forum for community made plugins and further discussion.
In this guide we dive into how to create a Baserow plugin from scratch, give you example plugins to get inspiration from and discuss how to publish your plugin.
We highly recommend using the Step by step tutorial on plugin creation using the plugin boilerplate which will setup a basic Baserow plugin ready for you to start working on.
To instantiate the template, execute the following commands:
$ cd ~/baserow
$ pip install cookiecutter
$ cookiecutter gl:baserow/baserow --directory plugin-boilerplate
Additionally, we have created two example plugins to show plugin authors how to do common things with a plugin.
The Geo plugin is an example plugin which adds a new "Point" field type. It shows how to:
- Install and enables a postgres extension (only when Baserow is running in the all-in-one image when using an embedded database)
- Install extra system packages using apt-get
- Add custom backend python and frontend node dependencies
- Add a new field type, with custom components and scss
The Example formula plugin
adds a new formula function called timezone
. It shows how to :
- Add a new formula function to Baserow
- Use a custom plpgsql stored procedure to implement the new formula function
- Use a migration to add the stored procedure
A Baserow plugin is fundamentally a folder named after the plugin, containing a
backend
and/or a web-frontend
folder. Baserow has two main services, a
Django backend
API server and a Nuxt frontend
web-frontend
server. A Baserow plugin can plug into either both or just one of these
services by populating the respective plugin sub-folder.
Since the backend
service is built with Django, the backend
sub-folder in a plugin
should be a Django app.
Similarly, the web-frontend
service is built using Nuxt.js, and so the web-frontend
plugin sub-folder should contain a Nuxt (
v2) module.
The current Baserow Plugin API Version is
0.0.1-alpha
.
All the Baserow official images ship with the following bash scripts which are used to
install plugins. They can be used either in a Dockerfile at build time to bake a plugin
into a Docker image or to install a plugin into an existing Baserow container at
runtime.
install_plugin.sh
can be used to install a plugin from an url, a git repo or a local
folder on the filesystem.
You can find these scripts in the following locations in our images:
/baserow/plugins/install_plugin.sh
/baserow/plugins/uninstall_plugin.sh
/baserow/plugins/list_plugins.sh
These scripts expect a Baserow plugin to follow the conventions described below.
The install_plugin.sh/uninstall_plugin.sh
scripts expect your plugin to have a
specific structure as follows:
├── plugin_name
│ ├── baserow_plugin_info.json (A simple json file containing info about your plugin)
│ ├── backend/ (Your plugins django app which will be installed into the backend)
│ │ ├── setup.py
│ │ ├── build.sh (Called when installing the plugin in a Dockerfile/container)
│ │ ├── runtime_setup.sh (Called on first runtime startup of the plugin)
│ │ ├── uninstall.sh (Called when uninstalling the plugin in a container)
│ │ ├── src/plugin_name/src/config/settings/settings.py (Optional Django setting file)
│ ├── web-frontend/ (Your plugins nuxt module which will be installed into the web-frontend)
│ │ ├── package.json
│ │ ├── build.sh (Called when installing the plugin in a Dockerfile/container)
│ │ ├── runtime_setup.sh (Called on first runtime startup of the plugin)
│ │ ├── uninstall.sh (Called when uninstalling the plugin in a container)
│ │ ├── modules/plugin-name/module.js (Your plugins module file)
The backend and web-frontend sub folders come with three bash files which will be automatically called by Baserow's plugin scripts during installation and uninstallation. You can use these scripts to perform extra build steps, installation of packages, and other docker container build steps required.
build.sh
: Called when a plugin is built into a Dockerfile, or on container startup if a runtime installation is occurring.runtime_setup.sh
: Called when the first time a container starts up after the plugin has been installed, useful for running superuser commands on the embedded database if it exists.uninstall.sh
Called on uninstall, the database will be available and so any backwards migrations should be run here.
The baserow_plugin_info.json
file is a json file, in your root plugin folder,
containing metadata about your plugin. It should have the following JSON structure:
{
"name": "TODO",
"version": "TODO",
"supported_baserow_versions": "1.29.3",
"plugin_api_version": "0.0.1-alpha",
"description": "TODO",
"author": "TODO",
"author_url": "TODO",
"url": "TODO",
"license": "TODO",
"contact": "TODO"
}
When using install_plugin.sh --url URL_TO_PLUGIN_TAR_GZ
or install_plugin.sh --git URL_TO_PLUGIN_REPO
the plugin archive/repo should contain a
single plugins
folder, inside which there should a single plugin folder following the
structure above and has the same name as your plugin. By default,
the plugin boilerplate generates a repository with this structure.
For example a conforming tar.gz archive should contain something like:
├─ * (an outermost wrapper directory named anything is allowed but not required)
│ ├── plugins/
│ │ ├── plugin_name/
│ │ │ ├── baserow_plugin_info.json
│ │ │ ├── backend/
│ │ │ ├── web-frontend/
Now you have created a plugin, lets go into more detail of how to actually extend and customize Baserow using your plugin.
First you should read the following documentation for a basic introduction to Baserow's technical architecture:
If your plugin needs to store state, you should only ever do this in:
- The database being used by Baserow
- Using Django's default storage mechanism
- The Redis being used by Baserow but only for non-persistent state like a cache that is fine to be destroyed at any moment.
Never store any state in your plugin folder itself inside the container. This folder is deleted and recreated as part of the plugin installation process and any state you store inside it can be lost.
Your backend plugin is just a normal python module which will be installed into the
Baserow virtual environment using pip
by install_plugin.sh
. If using the plugin
boilerplate you can add any python requirements to the pip requirements file found
at backend/requirements/base.txt
.
When the Baserow backend Django service starts up it looks for any plugins in the plugin
directory which have a backend
sub-folder. If it finds any it assumes
the backend/src/plugin_name/
sub folder contains a Django App and adds it to the INSTALLED_APPS
. This means that
your backend plugin must be a Django app whose name exactly matches the name of the
plugin folder.
In your plugin's Django app you can do anything that you normally can do with a Django
app such as having migrations, using the ready()
method to do startup configuration
etc.
Baserow has a number of registries which are used to dynamically configure Baserow. For
example the field_type_registry
contains various implementations of the FieldType
class.
Each registry contains various implementations of a particular "interface" class. A
registry in Baserow is simply a singleton dictionary populated by apps in their ready
method. Then Baserow's various API endpoints will use these registries at runtime.
So in your plugin's Django Apps ready
method is where you should import any relevant
registries and register your own implementations of field types.
For example, the plugin_registry
is used to register implementations of the
baserow.core.registries.Plugin
interface. You can create your own class which
implements this base class and register it with the plugin_registry
by:
from baserow.core.registries import plugin_registry
from django.apps import AppConfig
class PluginNameConfig(AppConfig):
name = "my_baserow_plugin"
def ready(self):
from .plugins import PluginNamePlugin
plugin_registry.register(PluginNamePlugin())
You can see all the different things you can dynamically register into Baserow with your
plugin by searching the Baserow codebase and inspecting the registry.py
and
registries.py
files.
Your web-frontend plugin is just a normal node package which will be installed into
Baserow's node_modules using yarn
by install_plugin.sh
. You can add any extra
frontend requires to your web-frontend/package.json
.
The Baserow web-frontend nuxt app also follows the registry pattern that the backend has. This means it has an equivalent frontend registry for most backend registries where it makes sense. So if you were to registry a new field type in the backend registry then also make sure to registry a new field type in the frontend registry also.
The easiest way to share you plugin with others is by making a public git repository using GitLab, GitHub or some other git host. Once you have pushed your plugin folder to the git repository then anyone can then install your plugin following the steps in the Plugin Installation guide.
Also, please share and post about your plugin on our Plugin community sub-forum!
Check out the following guides in the plugin section which go into more specifics on say creating a new field type: