Simplified EdgeDB Setup for Modern Database Management

A Step-by-Step Guide to Setting Up EdgeDB for Beginners

Kristijan Grozdanovski
9 min readSep 28, 2023

Welcome to the world of modern database management with EdgeDB! Whether you’re a software developer, data scientist, or a tech enthusiast eager to explore new technologies, EdgeDB promises to revolutionize the way you work with data. In this article, I’ll walk you through a simplified and more verbose setup, inspired by my personal struggle to grasp some of the concepts behind this novel piece of software and how to integrate it with the old and familiar project setups.

I will present you with three different ways to setup and interface with the database using a very simple python script as a demo client.

Prerequisites

This guide assumes you have already installed Python and/or Docker installed on your system. I use Python only to showcase a demo database client application therefore you can choose to use your own program written in any language which has an EdgeDB Client Library.

This guide also assumes you are running Linux on your host, however, everything works just fine on Windows as well. In order to keep this article as brief as possible, Windows-specific alternatives for certain commands are omitted but you can find them in the official documentation linked throughout this page.

Project Structure

The following project structure supports all three approaches described in this article however please note that not all files are used in every example. For the sake of brevity, I will reuse the same structure and files for all options.

my_project/

├── dbschema/ # Directory for your schema definition (.esdl) files
├── default.esdl # Define your database schema here
├── migrations/ # Directory for database migration files

├── edgedb.toml # EdgeDB configuration file

├── main.py # Your Python client application code

├── requirements.txt # Python dependencies list (if using Docker)

├── Dockerfile # Dockerfile for containerization (if needed)

├── docker-compose.yml # Docker Compose file (if using Docker)

└── ...

The edgedb.toml and dbschema/migrations file and directory will be automatically created by the EdgeDB CLI.

EdgeDB Demo Schema

We need some sort of structure that we can test our client against. Add the following to your dbschema/default.esdl file:

module default {
type Person {
required name: str;
}

type Movie {
title: str;
multi actors: Person;
}
};

Python Client Source-code

We will be testing our setup with a synchronous client, however, keep in mind that EdgeDB and the Python client library also support asynchronous requests.

Add the following code to your main.py file:

import edgedb

# Establish a connection to the EdgeDB instance
client = edgedb.create_client()

try:
# Insert data into the database
insert_data_query = r'''
INSERT Person {
name := 'Tom Cruise'
};
INSERT Person {
name := 'Val Kilmer'
};
INSERT Movie {
title := 'Top Gun: Maverick',
actors := (
select Person
filter .name in {
'Tom Cruise',
'Val Kilmer'
}
)
};
'''

client.execute(insert_data_query)
# Query for movies and the
query = r'''
SELECT Movie {
title,
actors: {
name
}
}
'''

# Execute the query
result = client.query(query)

# Print the results
for movie in result:
print(f"Movie: {movie.title}")
for actor in movie.actors:
print(f" Actor: {actor.name}")

except Exception as e:
print(f"An error occurred: {e}")
finally:
# Close the connection when done
client.close()

Option 1: Local Code and Database

Everything runs on the host, bare-metal

This is the simplest setup, suitable for both develop and bare-metal servers. The following is based on the official Quickstart Guide.

1. Installation: Begin by installing EdgeDB on your machine. On Linux we can do this by running

curl https://sh.edgedb.com --proto '=https' -sSf1 | sh

2. Initialize Your Project: Create a project directory as described and initialize it as an EdgeDB project:

edgedb project init

This is an interactive command which will scaffold your project by creating the necessary structure and files unless they already exist. Because we already defined a dbschema/default.esdl file, that one will be skipped and instead we will only see a new edgedb.toml file created under the project root directory.

This command will also spin up an EdgeDB server and “link” your current directory to that server, meaning all CLI commands you run will be executed against that instance unless unlinked.

More information regarding EdgeDB projects and instances as well as some clarification on what they actually are can be found here.

3. Generate Migrations: Create Database Migrations using the EdgeDB CLI

As you have noticed at this point, EdgeDB is designed to manage migrations instead of forcing the developer to rely on functionalities from ORMs.

This works by comparing your schema definition inside dbschema/default.esdl with the schema currently defined inside the database instance itself.

edgedb migration create

Skip this step if you are using a project with existing EdgeDB migrations.

4. Migrate Your Schema: Apply all migrations to the database:

# This command is an alias for `edgedb migration apply`
edgedb migrate

5. Setup the Application: Prepare a virtual environment and install Python dependencies:

# Navigate to the directory where the virtual environment is located
cd /path/to/project

# Create a Python virtual environment
python -m venv venv

# Activate the virtual environment
source venv/bin/activate

# Install the required Python dependencies
pip install edgedb

6. Test the Application: Start the Python application by running:

# From within the Python venv, run
python main.py

In the console we expect to see Python printing out our movie and the list of associated actors. That should look something like this:

Movie: Top Gun: Maverick
Actor: Tom Cruise
Actor: Val Kilmer

Option 2: Local Code and Dockerized Database

The code runs on the host while EdgeDB is in a Docker container

Let’s take our setup and step further and dockerize our EdgeDB instance. While the CLI is very straightforward to use for setting up EdgeDB, there are many reasons why you may want or need to have EdgeDB running from within a Docker container.

With this in mind, the good folks at EdgeDB have prepared an official image for us to use, as well as documentation to accompany it.

Let’s dive into the steps to set this up:

1. Create and run an EdgeDB Docker container

docker run \
--name edgedb \
-e EDGEDB_SERVER_SECURITY=insecure_dev_mode \
-v /my/data/directory:/var/lib/edgedb/data \
-v ./dbschema:/dbschema \
-d edgedb/edgedb

Please replace /my/data/directory with an actual directory on your system.

Note: Data persistence will not work on Windows. You will have to set up a Docker volume and bind to that instead. More info here.

By default, during the bootstrapping phase, the EdgeDB container will look for migrations in your dbschema/migrations directory and execute them. Therefore, if you are continuing here from the previous section where we already created migrations using the EdgeDB CLI on the host, you can skip the next two steps.

2. Create database migrations

docker exec edgedb edgedb --tls-security=insecure \
-H localhost migration create --non-interactive

Despite running everything inside the container, and even if we previously ran edgedb project init on the host, there is no edgedb.toml file within the container itself, therefore we have to explicitly define the instance connection parameters. Keep in mind that we are simply using the EdgeDB CLI bundled with the Docker image containing the server.

You should now see a new migrations/ directory under dbschema/ or if you already had it created manually, you will notice a new file inside it named something like 00001.edgeql .

Troubleshooting: If you get a Connection Timeout after running this command, it may be because the EdgeDB server is not yet up-and-running. Give it a few minutes and try again.

3. Apply database migrations

docker exec edgedb edgedb --tls-security=insecure -H localhost migrate

4. Define an EdgeDB Remote Instance

On the host machine, we will use the EdgeDB CLI to define a remote instance. You can think of this as a connection configuration which can later be used by projects.

The following process is the same for any server, regardless if on localhost or some external address. Run the following command and follow through the interactive configuration:

edgedb instance link
Specify server host [default: localhost]:
> localhost
Specify server port [default: 5656]:
> 5656
Specify database user [default: edgedb]:
> edgedb
Specify database name [default: edgedb]:
> edgedb
Unknown server certificate: SHA1:77070415... Trust? [y/N]
> y
Specify a new instance name for the remote server
[default: localhost]:
> edgedb_docker

5. Configure project to use remote instance

We now need to associate our current project directory with the instance we created. We will use the edgedb project init command to interactively configure the project with the following inputs:

edgedb project init
Do you want to initialize a new project? [Y/n]
> Y
Specify the name of EdgeDB instance to use with this project [default: ...]:
> edgedb_docker
Do you want to use existing instance "edgedb_docker" for the project? [y/n]
> y

6. Test the Application:

You may now test the application just like you did in the previous section by running

# Activate the virtual environment
source venv/bin/activate

# From within the Python venv, run
python main.py

Option 3: Fully Containerized Application

The client app and EdgeDB are both in Docker containers

You might think this would involve simply creating a custom, multi-stage Docker image derived from the official Python and EdgeDB CLI image, initializing the EdgeDB project non-interactively, installing the dependencies for Python via Pip and going on with your day.

Well so did I, but as it turns out you cannot run edgedb project init within a Docker container and hence the inspiration for this guide.

The EdgeDB Client can either use a linked instance created and associated via their CLI, or it can utilize environment variables to create a connection. This means that running edgedb project init on a project is not always required. Let’s take a look at this demo setup I made…

The docker-compose.yml file

version: '3.9'

services:
app:
image: app
container_name: app
environment:
- EDGEDB_DSN=edgedb://edgedb:5656?tls_security=insecure
volumes:
- .:/usr/src/app # Bind the current directory to the container
networks:
- internal
edgedb:
image: edgedb/edgedb
container_name: edgedb
env_file:
- "./.env"
volumes:
- dbdata:/var/lib/edgedb/data # Data persistence
- "./dbschema:/dbschema" # Schema persistence
ports:
- 5656:5656
networks:
- internal
volumes:
dbdata:
networks:
internal:
driver: bridge

The Dockerfile file

FROM python:3

WORKDIR /usr/src/app

COPY ./requirements.txt /install/requirements.txt
RUN pip3 install -r /install/requirements.txt

CMD [ "python", "-u", "./main.py" ]

The .env file

EDGEDB_SERVER_SECURITY=insecure_dev_mode
EDGEDB_SERVER_ADMIN_UI=enabled
EDGEDB_SERVER_BIND_ADDRESS="0.0.0.0"

And requirements.txt

edgedb==1.6.0

We can now get the project rolling in a few short, familiar steps…

1. Build the Docker image for our client application

docker build -t app .

2. Run the containerized EdgeDB server

docker-compose up -d edgedb

At this point you will have a running EdgeDB server container and if you already had database migrations defined in your dbschema/migrations directory then they will have been executed as well. If this is the case then continue to step 5, otherwise proceed with the next steps.

3. Create database migrations

For the sake of demonstrating a fully-containerized setup we will not use the EdgeDB CLI on the host (if installed) and will rely on the CLI bundled with the EdgeDB Docker image.

This process is similar to the steps from Option 2. of this guide except this time we use docker-compose exec instead of docker exec :

docker-compose exec edgedb edgedb --tls-security=insecure -H localhost migration create --non-interactive

4. Apply database migrations

docker-compose exec edgedb edgedb --tls-security=insecure -H localhost migrate

5. Test the application

This time we run our Python application as a Docker container:

docker-compose up app

Since we are not running the command in detached mode, in the terminal we should see something like

Attaching to app
app | Movie: Top Gun: Maverick
app | Actor: Tom Cruise
app | Actor: Val Kilmer
app exited with code 0

Important notes

Notice how in the CLI commands we use --tls-security=insecure as well as ?tls_security=insecure . This is possible thanks to the environment variable EDGEDB_SERVER_SECURITY=insecure_dev_mode , which is explained in detail here. This enables us to connect to the EdgeDB server without configuring any SSL files on the client application, as well as to access the Admin Web UI without having to set up any credentials.

Of course this makes the whole setup totally insecure and inadequate for a production environment. Perhaps we can explore a more secure setup in some future article?

Exploring the Built-In Web UI

EdgeDB comes with a handy built-in web-based administration interface that makes visualizing and exploring your database very straightforward. Here’s how to access it:

  1. Open Web UI: To access the web UI, open your web browser and navigate to http://localhost:5656/ui ;
  2. Database Exploration: Once logged in, you will see a grid of all the databases created within the database server. You can view the one we created by clicking on the grid box named edgedb ;
  3. Schema Visualization: One of the highlights of the web UI is the ability to visualize your schema. You can navigate to the Schema view from the left-hand side menu.

As of the time of writing, the UI lacks some visual cues that it is still loading data from the backend so if you don’t see anything but the client app works, give it a minute.

Conclusion

EdgeDB empowers you to manage data in a new, more intuitive way, making it a valuable asset for software engineers, data scientists, and innovators in different fields. I hope that by following this guide your setup has been simplified or at the very least have a more clear idea of how everything is meant to work together.

--

--