Working with 3DCityDB Series
This blog is part of a step-by-step 3DCityDB tutorial series for beginners working with CityGML, PostgreSQL, PostGIS, and 3D city digital twins.
In this blog, you will learn to create an Empty Spatial Database for CityGML. By the end of this part, you will:
This is Part 3. Some readers will land directly here from Google. To give an overview, in the previous parts of this series, we explored what digital twins are, why they matter for modern cities, and how 3DCityDB fits into the larger ecosystem of CityGML-based urban digital twins. We also walked through the software requirements and preparation steps needed before working with real 3D city data.
Now it’s time to get our hands dirty.
In this part, we move from preparation to execution by setting up the core foundation of 3DCityDB: an empty spatial database built on PostgreSQL and PostGIS. This database is where every building geometry, surface, attribute, texture, and semantic relationship from CityGML will ultimately live.
If you think of a digital twin as a living system, then this database is its backbone. Without it, 3DCityDB cannot store, query, or manage 3D city models efficiently.
This blog will guide you step-by-step through:
No prior database expertise is required. Each action is explained in simple terms, with clear reasoning behind it, so you understand what’s happening under the hood—not just which buttons to click.
By the end of this tutorial, you’ll have a fully initialized 3DCityDB database, ready to accept CityGML datasets and power the next stages of your city-scale digital twin. No data yet, no visualizations yet—just a solid foundation that ensures everything you build next is stable, scalable, and standards-compliant.
Let’s begin by connecting to PostgreSQL and creating your first CityGML-ready spatial database that will hold your first 3D city.
Now that PostgreSQL and PostGIS are installed (Working with 3DCityDB blog series, part 2), the next step is to create a database server connection that will later host our CityGML data. For this, we’ll use pgAdmin 4, the official graphical interface for managing PostgreSQL databases.
pgAdmin is a graphical interface that allows you to create databases, run SQL commands, and manage spatial extensions without touching the command line.
On Windows:
After a few seconds, pgAdmin will open in your default browser window.

You’ll notice a clean interface with a tree panel on the left. This panel represents database servers, databases, schemas, and extensions. Think of it as a file explorer, but for databases.

Since this is your first time using pgAdmin, you need to tell it where your PostgreSQL server lives.
On the home screen, under Quick Links, click on:
“Add New Server”
This opens the Register-Server dialog.

General Tab
Here, you only need to provide a friendly name.
Connection Tab
This is where pgAdmin actually connects to PostgreSQL.
Fill in the following details:
⚠️ If you don’t remember the password, don’t worry, this is very common.
You can reset it using this guide:
👉 https://hassanannajjar.medium.com/how-to-fix-error-password-authentication-failed-for-the-user-in-postgresql-896e1fd880dc
Once all fields are filled, click Save.

After saving, you’ll see your newly registered server appear in the left panel.
Expand it, and you should see:
If you can expand the server without errors, 🎉 your PostgreSQL connection is working correctly.

You’re now ready to create a new database for 3DCityDB, but first, let’s understand some related terminologies.
When you first open pgAdmin 4, the left panel shows a tree structure with several technical terms. If you’re new to databases, this can look intimidating—but the concepts are actually quite intuitive once you relate them to real life.
Let’s break them down one by one.
Think of a database server as the building.
A database server is the running PostgreSQL service on your machine (or on another computer). It’s the engine that listens on a port (usually 5432) and handles all requests to store, retrieve, or update data.
In our setup:
📌 Example:
Your laptop is the building. PostgreSQL is the caretaker managing all rooms inside it.
Databases are individual rooms inside the building.
Inside one database server, you can create multiple databases, each completely separate from the others. Data in one database cannot be accessed from another unless explicitly linked.
For 3DCityDB:
📌 Example:
Each room has its own purpose.
Schemas are organized cupboards inside a room.
A schema is a logical container that organizes tables, views, and functions inside a database. Instead of throwing everything into one place, schemas help keep things clean and structured.
In PostgreSQL:
📌 Example (very important for 3DCityDB):
This separation is one of the reasons 3DCityDB scales so well for large cities.
Extensions are feature add-ons for the database.
By default, PostgreSQL understands tables and text, but it does not understand geography or 3D geometry. Extensions add these capabilities.
The most important extension for us is PostGIS.
PostGIS adds:
📌 Without PostGIS:
PostgreSQL sees a building as random numbers.
📌 With PostGIS:
PostgreSQL understands:
This is why PostGIS is mandatory for 3DCityDB.
Once all of these are in place, 3DCityDB can:
Now, since the database server is in place, let's create an empty database inside it.
With pgAdmin 4 connected to your PostgreSQL server, the next step is to create a dedicated database that will hold your 3D city model. This database will later be transformed into a full 3DCityDB instance.

A dialog window opens where you define the basic properties of the new database.
Enter the following:
Once done, click Save.

You will now see BerlinDigitalTwin listed under the Databases section in the Object Explorer. At this stage, the database exists, but it is still a regular database without any spatial capabilities.

3DCityDB relies heavily on spatial data types and geometry operations. To support this, we need to enable PostGIS extensions inside the newly created empty database.
Make sure the BerlinDigitalTwin database is selected in the Object Explorer. Then click on the Query Tool icon in the top toolbar to open a new SQL editor window.


Inside the query editor, type the following command:
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_raster;

Click the Run button (▶) to execute the command.
If everything is configured correctly, PostgreSQL will install the PostGIS extensions inside this database. This may take a few seconds.

To confirm the installation:
You should now see PostGIS extensions listed in the extensions tree.

While 3DCityDB primarily works with vector geometries, certain CityGML workflows and dependencies expect raster support to be available. Enabling postgis_raster upfront prevents downstream issues that are otherwise difficult to debug.
This database is now ready to be transformed into a 3DCityDB schema, which we’ll do next by applying the official 3DCityDB SQL scripts.
At this point, our database understands geometry — but it still doesn’t understand cities. That’s where the 3DCityDB schema comes in.
At this point, we have:
Now comes the most important step: transforming this empty database into a 3DCityDB-ready CityGML database.
We can proceed to install the actual 3DCityDB schema.
PostgreSQL on its own does not understand CityGML. It doesn’t know what a building is, how surfaces relate to geometry, or how semantic attributes should be stored. This is why 3DCityDB provides a set of official SQL and PL/pgSQL scripts.
PL/pgSQL stands for Procedural Language / PostgreSQL. It is PostgreSQL’s built-in programming language that lets you write logic, rules, and automation directly inside the database.
3DCityDB SQL Scripts:
Instead of manually creating tables, we simply run these scripts once, and the database becomes CityGML-aware.
To apply the 3DCityDB schema, we first need to tell the scripts how to connect to our database.
Navigate to the following folder on your system:
C:\RTG_Schulungskurs_2016\Importer-Exporter-Tool\3dcitydb\postgresql\ShellScripts\Windows
Inside this folder, locate the file named:
CONNECTION_DETAILS.bat
Open this file using a text editor such as Notepad++ or Notepad.

Inside the file, you’ll see a section where database parameters are defined. Update the values so they match your local PostgreSQL setup.
Use the following configuration:
:: Provide your database details here -----------------------------------------
set PGBIN=C:\Program Files\PostgreSQL\18\pgAdmin 4\runtime
set PGHOST=127.0.0.1
set PGPORT=5432
set CITYDB=BerlinDigitalTwin
set PGUSER=postgres
::-----------------------------------------------------------------------------
A quick explanation of what these mean:
Once updated, save and close the file.
Now comes the actual schema creation.
This step is where a regular spatial database officially becomes a CityGML-aware 3D city database.
In the same folder, double-click on:
CREATE_DB.bat

A command-line window will open and guide you through a few configuration inputs.
You will be prompted for several values. Enter them exactly as shown below.
Spatial Reference Identifier (SRID)
Enter:
25833
This corresponds to ETRS89 / UTM Zone 33N, commonly used for German datasets.
Height System EPSG Code
Simply press ENTER to accept the default.
SRSName (OGC-compliant CRS identifier)
Enter:
urn:ogc:def:crs,crs:EPSG:6.12:25833,crs:EPSG:6.12:5783
This defines both horizontal and vertical coordinate reference systems.


When prompted for the PostgreSQL password, type the password you set during installation.
⚠️ Important note:
While typing, the cursor will not move, and no characters will appear on the screen. This is normal. Type the password carefully and press ENTER.
The script will now begin creating the 3DCityDB schema. This process usually takes about one minute.
Once finished, you’ll see a confirmation message in the command window indicating successful completion.

Press any key to close the window.
Go to pgAdmin 4 and refresh Schemas by right-clicking on it.

Now you would be seeing the citydb schema created under Schemas.

At this point, you have successfully:
Our database is no longer empty. It is now a fully functional 3D City Database, capable of storing buildings, geometries, textures, and semantic relationships at the city scale.
This hierarchy is important: CityGML does not live directly in PostgreSQL — it lives inside a structured 3DCityDB schema, which itself lives inside a spatial database.
You’ve now completed one of the most important milestones in the 3DCityDB workflow — setting up a fully functional 3D city database that’s ready to store real CityGML data.
By registering your database server, creating a spatial database, enabling PostGIS, and applying the official 3DCityDB schema, you’ve transformed an empty PostgreSQL instance into a CityGML-ready backend. This database will act as the semantic core of your digital twin, capable of storing buildings, surfaces, attributes, and relationships at the city scale.
While this setup step may feel technical, it’s a one-time effort that unlocks everything that follows — importing CityGML files, exporting 3D formats, running spatial queries, and visualizing your city in the browser.
At this stage, our system doesn’t yet show a city — but it fully understands how to store, query, and manage one.
In the next part of this series, we’ll finally bring data into the system by importing a real CityGML dataset and exploring how 3DCityDB organizes buildings, geometry, and semantics inside the database.
Follow along, and your digital twin will start taking shape.
If you’re following till here:
I’d love to hear how it went.
💬 Drop a comment below if:
Your questions help shape the next posts in this series.
See you in Part 4!
Have a question? Working on a digital twin?
👇 Drop a comment — I’d love to hear what you’re building.
Let’s learn and experiment together. 🚀🌍