Over a million developers have joined DZone.

Your Basic CRUD: A Simple Tarantool Web App (Tarantool 101, Guide 4A)

DZone's Guide to

Your Basic CRUD: A Simple Tarantool Web App (Tarantool 101, Guide 4A)

Learn how to build a complete CRUD app using only the in-memory database Tarantool and HTML/CSS/JS—no additional backend language or database needed.

· Web Dev Zone ·
Free Resource

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Image title

Tarantool powers some of the largest stacks in the world but what can it do for a simple web app? Well, for starters, it’s probably the fastest option you can choose, both in terms of raw speed, since it’s RAM-based, but also in terms of development time—since it’s the only tech you’ll need to add to your server (it includes both an application server and a database). Also, the Tarantool ecosystem takes care of other tooling you may have needed to outsource otherwise. For example, you won’t need a separate tool to keep Tarantool alive because Tarantool ships with the handy tarantoolctl.

What we’ll be making is a classic “Todo” app that allows you to make a task (“create”), list your tasks (“read”), edit tasks (“update”), and delete tasks (“delete”). This article will be divided into two parts, the first covering “create” and “read,” and the second covering “update” and “delete.” It stands on its own but you may find it helpful to refer to Tarantool 101 Guide 1 or Guide 2. Also, note that I am working on a Digital Ocean server running Ubuntu 16.04. Finally, you can see the code for the app here and a demo here.

Well, let’s get started.

First copy and paste the entire script from here to install Tarantool 1.9 (choose “Xenial”).

Next, we'll use cmake to install the Tarantool HTTP module for our server:

git clone https://github.com/tarantool/http.git
cd http && cmake . -DCMAKE_BUILD_TYPE=RelWithDebugInfo
make install

As we discussed in Tarantool 101 Guide 2, it is customary to install and maintain Tarantool applications as two identically named files in two different locations, one for config and one for operations.

So let’s make a config crud.lua in /etc/tarantool/instances.enabled:


if not box.space.crudspace then s = box.schema.space.create('crudspace')   
  s:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) 

local m = require('crud').start({...})

This file creates a new space called “crudspace” if none exists and also creates an index (note that all Tarantool spaces must have at least one index). Finally, it starts the server by calling the start function from the sister file in the other location. Now we’ll make the sister code file, also named crud.lua, in /usr/share/tarantool:

function create(req)
  local selfVar = req:post_param(data)
  for k,v in pairs(selfVar) do

function read(self)
  return self:render({ json = box.space.crudspace:select() })

function start()
  local server = require('http.server').new(nil, 8080, {app_dir='/usr/share/tarantool'})
  server:route({ path = '/', file='index.html'})
  server:route({ path = '/read'}, read)
  server:route({ path = '/create'}, create)

return {
  start = start

This is, in fact, the entirety of our Tarantool code for “create” and “read,” no additional DB connection file necessary! Basically, our file includes three functions, one for creating tasks, one for reading tasks, and one for running the server. In the create function, we accept a posted request from the front-end which gets converted to a Lua table and then inserted into the database. One thing I want to point out here is that auto_increment has been deprecated for sequences in Tarantool, but since it is a bit shorter, I am using it to keep the code concise (sequences actually add quite a bit of additional functionality but there isn't time to explain them here).

Next, we have a read function, which basically does a select statement over the whole space, converts it to JSON, and then sends it back to the JavaScript on the front-end that requested it.

Finally, the start function runs our server (specifying a default directory, app_dir), then deals with route handling.

Ok, now we’ll set up our HTML/CSS/JS files for the front-end. In /usr/share/tarantool, make two directories, 'public' and 'templates.' In templates, put an index.htmland in public, make a css and a js folder. You’re welcome to put some CSS in the css folder to make the app look nicer (I used the CSS file from the Skeleton framework). Then add a main.js file in the js folder.

Note that our HTML file needs to be specified on the route route in the start function in the "operations" crud.js (as done above). Otherwise, it’s quite basic, with a title, a form for adding todo items, and then a <div> for attaching the JavaScript generated todos at the bottom:

<!DOCTYPE html>
    <link rel="stylesheet" href="css/main.css">
    <title>Tarantool CRUD</title>

    <h3>Tarantool Todos</h3>
    <div id="todoform">
      <form id="addatodo">
        <label for="todoname">add a todo</label>
        <input id="todoname" type="text" name="todoname">
        <input type="submit" id="submit" value="submit">

    <div id="div1"></div>

  <script src="js/main.js"></script>

Now let’s proceed to the JavaScript. Each time the root route is hit, we’ll use fetch to call Tarantool on the backend, then we’ll dynamically build the todos and attach them to the DOM by for-of looping through the Tarantool response:

.then(response => response.json())
.then(data => {
  mainNode = document.getElementById("div1")
  for (const x of data) {
    let todo = document.createElement("p")
    let todo_text = document.createTextNode(x[1])
}).catch((err) => {          

After that we’ll handle the submission of new todos through the form:

let toDoForm = document.getElementById("todoform")
toDoForm.addEventListener('submit', function(event){
  let todo = document.getElementById("todoname")
  let data = new URLSearchParams()
  data.append('todovalue', todo.value) 
  fetch('/create', {
    method: "POST",
    body: data
  }).then((response) => {
  }).catch((err) => {

This posts to Tarantool each time a todo is added, then calls the route route and rebuilds the DOM, including the new todo. It is not necessarily ideal to rebuild the DOM each time, but this is a Tarantool exercise after all!

Finally, we’ll start our app withtarantoolctl start crud.lua . You can visit your IP address at port 8080 to bring it up and you can check its status with tarantoolctl status crud.lua. You may be surprised at how robust your app is running under tarantoolctl. Come back in a week and check on it!

Image title

Well, that’s it for the “create” and “read” functionality for our app. In the next article in the series, we will proceed with “update” and “delete.”

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

crud ,tarantool ,web dev ,web application development

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}