Mahdi.Kh
September 18, 2026
Using Maxwell, we read data changes from the primary database and put them on RabbitMQ, and finally build an indexer service that processes the messages placed on RabbitMQ and indexes the data on Typesense.
In this part, we use a small prebuilt blog management service and implement fast search on this project using CDC.
Our service is a simple blog that gives us the ability to create, delete, and edit content. This project uses Golang as the backend language and MySQL as the primary database. Using CDC, we can read data changes from the blog table and store these changes in the typesense database.
You can see and download the project's final source code on GitHub. To run the project, first go to the project folder using the terminal, and then run the project with Docker using the command below:
And finally, you can shut down the project using the command below:
If you're not familiar with Docker or haven't installed it, it's best to install Docker first, and this will also be a good opportunity to get a bit familiar with Docker.
And if you have make on your system, you can use the commands below inside the project folder to start up and shut down the services:
Before we start implementing, let's look at the final structure of what we want to have.
Overall, we'll use the following tools to build our project:
We use MySQL as the primary database for storing and maintaining content.
We use the Typesense database to full-text index the content for use in search. This way, our application can search the desired content very quickly and provide the results to our application's users.
We use RabbitMQ as a queue. This way, we put changes made on the primary database into this queue, and then, by processing the messages in the queue, we update the data on Typesense.
This way, we'll index all the data on Typesense instantly, without putting any load on our primary database.
We use Maxwell to read MySQL's logs and turn those logs into messages on RabbitMQ. This way, the changes we make to data in MySQL are stored as messages inside RabbitMQ.
We build an indexer application that reads the messages written to RabbitMQ and, based on these messages, indexes and updates the data on Typesense.
Our main application, whose responsibilities are split into two main parts:
Dashboard-related functionality for managing blog posts, which stores and updates data on the primary database (MySQL, in this case).
General functionality, including the home page, post detail pages, and searching content, which reads and displays data from Typesense.
The overall shape of our application will be as follows:
To set up Maxwell on MySQL, according to the documentation, we need to go through the following steps:
To do this, we can create a file with a conf extension at /etc/mysql/conf.d/. For example, I'll create this file named cdc.conf at /etc/mysql/conf.d/cdc.conf.
Then we put the following settings inside it:
In the settings above, we set the log format to row and enabled logging using log-bin. Whenever we use the log-bin directive, we also need to assign an ID to the MySQL server. Here, we assigned the number 1 as the ID for this MySQL server. If you have multiple servers or replicas, you should use different IDs.
In the last line, we specified that logging should be enabled only for the blog database. By default, using log-bin enables logging for every database. Using bin_do_db, we can restrict logging to just the databases we want. You can repeat this line once per database.
By removing every line that contains bin_do_db, we can enable logging for every database.
Quite often, these settings are already enabled by default, and we don't need to configure them again! To check whether they're enabled or not, you can run the following queries on your current database and check the result:
To do this, you need to connect to your database and run the following commands inside it:
In the first line, you can put your own password instead of maxwell123. Running the commands above creates a user named maxwell as well as a database named maxwell. This user will have full access to the maxwell database. We also grant this user read and replication access on every database. If you want maxwell to have access only to the blog database, you can use blog.* instead of *.*.
After Maxwell is enabled, this tool detects changes that happen in the database (such as INSERT, UPDATE, and DELETE) and produces each change as a message (usually in JSON format).
These messages are then sent to RabbitMQ so other services can use them. However, by default, Maxwell only publishes new changes from the moment it's enabled onward. Because of this, data that already existed in the database beforehand isn't sent to RabbitMQ. To cover this case, there's a feature called Bootstrap. Using Bootstrap, you can also extract the existing data in selected tables and send it to RabbitMQ just like new changes.
Here, we use this feature to index, on Typesense, the data that existed before Maxwell was enabled.
After completing the configuration, we can run maxwell and its bootstrapper separately:
Above, we ran two separate commands. The first command runs maxwell as a long-running process, meaning this service keeps running continuously and sends database changes to RabbitMQ.
The second command is maxwell-bootstrap, and running it creates a record in the bootstrap table, which causes maxwell to start the initial data load. You can also do this manually yourself, in which case you won't need the maxwell-bootstrap command.
Note: If you're using the project created in our GitHub repo, after running the project (how to run it is mentioned at the start of this post), you can go to
http://localhost:8081/to see the PHPMyAdmin dashboard and use it to inspect the database structure.
After running bootstrap and maxwell, if we have data in the current database, or if we make changes to the data, we should be able to see the messages that were sent in the RabbitMQ dashboard, under the exchange named maxwell.
In the chart above, we can see that in a short time window, 60 messages per second were sent to RabbitMQ. Next, we'll build a service that processes these messages and indexes the result on Typesense.
Note: If you're using the project created in our GitHub repo, after running the project you can go to
http://localhost:15672/and log in with the username admin and the password admin123.
This service is responsible for processing the messages that Maxwell writes onto RabbitMQ. Processing each message consists of creating, editing, or deleting an index entry.
If the user creates new content, that content is placed as a message on RabbitMQ, and then the indexer service processes this message and creates a new index entry on Typesense.
If the user edits existing content, that edit is placed as a message on RabbitMQ, and then the indexer service processes this message and updates the current indexed content on Typesense.
Based on the code above, depending on the type of message placed on RabbitMQ, we create, edit, or delete the index entry in Typesense. You can see the complete code on GitHub.
By running the indexer service, the data should get indexed in Typesense, and you can see the result in the typesense dashboard.
For example, in the image we can see that 290 items have been indexed in the posts collection.
Then, our main application can search through the indexed data and show the results to users:
Note: If you're using the project created in our GitHub repo, after running the project you can go to
http://localhost:8085/to see the blog service.
In the image above, whatever we search for in the search box, if it exists, the list of related posts will be shown to us.
Previous part: Introduction and Overview | CDC Pipeline