In this tutorial, you will build an Airline Dashboard — a fully functional internal tool that lets you browse, search, create, edit, and delete airline records stored in Couchbase. You'll use ToolJet's visual app builder and connect it to Couchbase using the Couchbase marketplace plugin, covering all 6 supported operations.
By the end, you'll have a deployed web app that your team can use immediately — no backend code, no frontend framework, no deployment pipeline required.
An Airline Dashboard with:
travel-sample datasetTo follow this tutorial, you will need:
travel-sample bucket loaded (see Couchbase Cluster Setup)Couchbase Capella is the easiest way to get started. It has a free tier and the Data API is available out of the box.
travel-sample and click Load Sample Datatravel-sample bucketSecurity Note: Never allow
0.0.0.0/0(all IPs). Always restrict access to specific IP addresses, even in development.
https://<cluster-id>.data.cloud.couchbase.comIf you prefer to run Couchbase locally:
docker run -d --name couchbase-server \
-p 8091-8096:8091-8096 \
-p 11210-11211:11210-11211 \
-p 18091-18096:18091-18096 \
couchbase:7.6.2Initialize the cluster:
http://<your-server-hostname-or-ip>:8091 in your browser (use localhost if running Docker on your local machine)Load the travel-sample bucket:
travel-sample and click Load Sample DataYour Data API endpoint is the base URL of the server running Couchbase:
http://<your-server-hostname-or-ip>:8091Use http://localhost:8091 only if Couchbase is running on the same machine as ToolJet. For remote servers, replace with the server's actual hostname or IP address.
Note: For self-managed clusters, the Data API is available on the same port as the management API. Ensure Data API is enabled in your cluster configuration.
docker run -d \
--name tooljet \
-p 80:80 \
tooljet/tooljet-ce:v3.16.0-LTSOpen http://localhost and create your admin account. For more setup options (Kubernetes, AWS, GCP, Azure), see the ToolJet self-hosting guide.
Step 9 of this tutorial uses Couchbase Full-Text Search. Create the index now so it's ready when you need it.
airline-name-indextravel-sampleinventoryairline collectionname field as textairline-name-indextravel-sampleinventoryairline collectionname field as textThe Couchbase integration is a marketplace plugin — you need to install it first.
You should see the Couchbase plugin with its red logo appear in your installed plugins list.
Now connect ToolJet to your Couchbase cluster:
Let's fetch airline data from the travel-sample dataset.
listAirlinesSELECT META().id AS doc_id, name, country, callsign, iata, icao
FROM `travel-sample`.`inventory`.`airline`
ORDER BY name
LIMIT 50You should see results in the preview panel — a list of airlines with their names, countries, and callsigns.
How it works: This SQL++ query runs against the
airlinecollection inside theinventoryscope of thetravel-samplebucket.META().idgives us the document ID, which we'll need for CRUD operations later.
Now let's create a second query that uses parameterized arguments — this is the recommended way to pass dynamic values in SQL++ because it prevents injection attacks.
listAirlinesByCountrySELECT META().id AS doc_id, name, country, callsign, iata, icao
FROM `travel-sample`.`inventory`.`airline`
WHERE country = $country
ORDER BY name
LIMIT 50{ "$country": "United States" }Why parameterized queries? Instead of concatenating user input directly into SQL++ strings (which risks injection attacks), Couchbase's
$parametersyntax sends values separately from the query statement. The plugin passes these through theargsfield in the Data API request body. You can also pass Query Options like{ "readonly": true, "timeout": "30s" }for additional control.
{{queries.listAirlines.data.results}}You should now see a table showing airline names, countries, callsigns, IATA codes, and ICAO codes.
Customize the table (optional):
doc_id → "Document ID")doc_id column if you don't want users to see it (but keep it — we'll need it later)Let's add the ability to view a single airline's full document when a user clicks a row.
getAirline:
travel-sampleinventoryairline{{components.table1.selectedRow.doc_id}}Drag a Modal component onto the canvas and add Text components inside it to display:
{{queries.getAirline.data.name}} — Airline name{{queries.getAirline.data.country}} — Country{{queries.getAirline.data.callsign}} — Callsign{{queries.getAirline.data.iata}} — IATA codeOn the Table component, add a Row clicked event handler:
getAirlineNow when you click any airline row, it fetches the full document and displays it in a modal:
Drag a Button component above the table, label it "Add Airline"
Drag a Modal component for the creation form. Inside it, add:
airlineName (label: "Airline Name")airlineCountry (label: "Country")airlineCallsign (label: "Callsign")airlineIata (label: "IATA Code")airlineIcao (label: "ICAO Code")airlineDocId (label: "Document ID", placeholder: "airline_9999")Create a new query named createAirline:
travel-sampleinventoryairline{{components.airlineDocId.value}}{
"type": "airline",
"name": "{{components.airlineName.value}}",
"country": "{{components.airlineCountry.value}}",
"callsign": "{{components.airlineCallsign.value}}",
"iata": "{{components.airlineIata.value}}",
"icao": "{{components.airlineIcao.value}}"
}createAirline, then Run query listAirlines (to refresh the table), then Hide modalTest it: Click "Add Airline", fill in the form, click "Create". The new airline should appear in the table.
Add an Actions column to the table with an "Edit" button
Create a new modal with the same form fields as Step 6, but pre-populated with the selected row's data:
airlineNameEdit default: {{components.table1.selectedRow.name}}airlineCountryEdit default: {{components.table1.selectedRow.country}}Create a new query named updateAirline:
travel-sampleinventoryairline{{components.table1.selectedRow.doc_id}}{
"type": "airline",
"name": "{{components.airlineNameEdit.value}}",
"country": "{{components.airlineCountryEdit.value}}",
"callsign": "{{components.airlineCallsignEdit.value}}",
"iata": "{{components.airlineIataEdit.value}}",
"icao": "{{components.airlineIcaoEdit.value}}"
}updateAirline → Run query listAirlines → Hide modalImportant: The Update operation performs a full document replacement (HTTP PUT), not a partial update. Make sure your document JSON includes all fields, not just the ones you changed.
Add a "Delete" button in the table's Actions column
Create a new query named deleteAirline:
travel-sampleinventoryairline{{components.table1.selectedRow.doc_id}}deleteAirline → Run query listAirlines (to refresh the table)Now let's add a search bar that uses Couchbase's Full-Text Search to find airlines by name.
Before continuing, ensure you have created the
airline-name-indexFTS index as described in the Prerequisites section.
Drag a Text Input component above the table, label it "Search Airlines" (searchInput)
Create a new query named searchAirlines:
travel-sampleinventoryairline-name-index{
"query": {
"match": "{{components.searchInput.value}}",
"field": "name"
},
"fields": ["name", "country", "callsign"],
"size": 20
}Add an event handler on the search input: On change → Run query searchAirlines
Update the Table's Data to conditionally show search results or all airlines:
{{components.searchInput.value
? queries.searchAirlines.data.hits.map(hit => hit.fields)
: queries.listAirlines.data.results}}Now when you type in the search bar, it performs a real-time Full-Text Search against Couchbase and displays matching airlines.
You've built a complete Airline Dashboard that demonstrates all 6 Couchbase operations in ToolJet:
| Operation | What You Built |
|---|---|
| SQL++ Query | Main airline listing with sorting |
| Get Document | Click-to-view airline details modal |
| Create Document | "Add Airline" form |
| Update Document | Inline edit functionality |
| Delete Document | Delete with confirmation |
| FTS Search | Real-time search bar |