This tutorial guides you through setting up a containerised development environment using Docker,
Visual Studio Code, .NET MAUI, and PostgreSQL. By the end, you will have a reproducible development
environment that includes everything needed for mobile app development with database support.
Architecture Overview
The development environment uses Docker to provide a consistent build environment across all
platforms. The Android emulator runs on your host machine (for performance and GPU access),
while the container handles building and deploying your app.
Fig. 1. Architecture overview
1. Install Docker Desktop
Docker Desktop provides a graphical interface for managing containers and includes everything
needed to run containerised applications on your computer.
Download Docker Desktop from the Docker website
and run the installer.
Warning
Docker Desktop on Windows requires WSL 2 (Windows Subsystem for Linux). If you don’t have it
installed, the Docker installer will prompt you to enable it. You may need to restart your
computer during this process.
After installation, Docker Desktop should start automatically. You can verify it’s running by
looking for the Docker whale icon in your system tray.
Log out and back in for the group change to take effect. Alternatively, you can install
Docker Desktop for Linux
if you prefer a graphical interface.
Verify Docker is installed correctly by opening a terminal and running:
1
docker --version
You should see output similar to Docker version 24.0.0 or higher.
2. Install Visual Studio Code and Extensions
Follow the installation instructions for your operating system on the
VSCode website.
Once VSCode is installed, you need to add the following extensions:
Extension
Extension ID
Purpose
Dev Containers
ms-vscode-remote.remote-containers
Develop inside Docker containers
Docker
ms-azuretools.vscode-docker
Manage Docker containers and images
Database Client
cweijan.vscode-postgresql-client2
Connect to and query PostgreSQL databases
.NET MAUI
dotnettools.dotnet-maui
.NET MAUI development support
AVD Manager
toroxx.vscode-avdmanager
Manage Android Virtual Devices
To install an extension, open VSCode and press Ctrl+Shift+X (Windows/Linux) or Cmd+Shift+X (Mac)
to open the Extensions panel. Search for each extension by name and click Install.
Fig. 4. Required VSCode extensions installed
3. Create the Project Structure
Create a new project folder with the required subdirectory for the dev container configuration.
mkdir MauiDevProject
cd MauiDevProject
mkdir .devcontainer
Open a terminal and run:
1
2
mkdir-p MauiDevProject/.devcontainer
cd MauiDevProject
Open the MauiDevProject folder in VSCode using File > Open Folder… or by running
code . from the terminal while in the project directory.
Your project structure should look like this:
1
2
MauiDevProject/
└── .devcontainer/
4. Create the Dockerfile
The Dockerfile defines the development container with all the tools needed for .NET MAUI
development, including the .NET SDK, MAUI workloads, Java JDK, and Android SDK.
Create a file called Dockerfile in the project root directory with the following content:
.NET SDK 9 - The latest .NET SDK for building MAUI applications
MAUI workloads - Required components for cross-platform mobile development
Java JDK 17 - Required by the Android SDK tools
Android SDK - Command-line tools for building and deploying Android apps
Platform tools - ADB and other utilities for communicating with Android devices
5. Configure Docker Compose
Docker Compose allows you to define and run multi-container applications. We will create a
configuration with two services: an application container for development and a PostgreSQL
database container.
Create a file called docker-compose.yml in the project root directory with the following content:
build - Builds the container using our custom Dockerfile instead of a base image
network_mode: service:db - This connects the app container directly to the database
container’s network. This means you can connect to PostgreSQL using localhost:5432 from
within the app container.
extra_hosts - Allows the container to connect to services running on the host machine
(such as the Android emulator) using the hostname host.docker.internal
volumes: postgres_data - This creates a named volume that persists your database data
even when containers are stopped or removed.
command: sleep infinity - This keeps the app container running so VSCode can connect to it.
Fig. 5. Docker Compose architecture diagram
6. Configure the Dev Container
The dev container configuration tells VSCode how to use the Docker Compose setup for development.
Create a file called devcontainer.json inside the .devcontainer directory with the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{"name":"MAUI Dev Environment","dockerComposeFile":["../docker-compose.yml"],"service":"app","workspaceFolder":"/workspace","customizations":{"vscode":{"extensions":["cweijan.vscode-postgresql-client2","ms-dotnettools.dotnet-maui","toroxx.vscode-avdmanager"]}},"remoteUser":"root"}
Note
Understanding the configuration:
dockerComposeFile - Points to your Docker Compose configuration
service - Specifies which container VSCode should connect to
workspaceFolder - The folder inside the container where your project files appear
customizations.vscode.extensions - Extensions to install automatically inside the container,
including the PostgreSQL client, .NET MAUI tools, and AVD Manager
Never commit database credentials or .env files containing passwords to version control.
The credentials in this tutorial are for local development only.
8. Open the Project in the Container
Now you can open the project inside the development container.
Press Ctrl+Shift+P (Windows/Linux) or Cmd+Shift+P (Mac) to open the command palette.
Type “Reopen in Container” and select Dev Containers: Reopen in Container.
Fig. 6. Building the container
Warning
The first time you do this, Docker will build the custom image and download the required
components (.NET SDK, MAUI workloads, Java JDK, Android SDK). This may take 10-15 minutes
depending on your internet connection. Subsequent starts will be much faster as the image
is cached locally.
Once the container is ready, you will see the project files in the Explorer panel, and the
bottom-left corner of VSCode will show “Dev Container: MAUI Dev Environment”.
Fig. 7. VSCode running inside the container
Verify the Development Tools
Open a terminal (Ctrl+ or Cmd+) and verify the development tools are installed:
1
2
3
4
5
6
7
8
# Check .NET version
dotnet --version# Check MAUI workloads
dotnet workload list
# Check Android SDK
sdkmanager --version
You should see .NET 9.x, the MAUI workloads listed, and the Android SDK manager version.
The Database Client extension allows you to browse and query your database directly from VSCode.
Click on the Database icon in the Activity Bar on the left side of VSCode.
Click the + button to create a new connection and select PostgreSQL.
Enter the following connection details:
Parameter
Value
Connection Name
MauiDevProject
Group
(leave blank)
Hostname
localhost
Port
5432
Username
dev_user
Password
dev_password
Database
devdb
Use SSL
No
Fig. 9. PostgreSQL connection configuration
Note
Because the app container uses network_mode: service:db, it shares the network namespace
with the database container. This means PostgreSQL is accessible at localhost:5432 from
within the app container.
Once connected, you can expand the connection in the sidebar to see databases, schemas, and tables.
10. Verify the Database Setup
Let’s verify the database connection is working by creating a simple table and querying it.
Create a test table
Expand the devdb database in the sidebar until you can see the public > Query element. Click on
the+ icon to create a new query called create_table. Enter the following SQL and execute it by
clicking the Run button:
Run a SELECT query to verify the data was inserted:
1
SELECT*FROMstudents;
Fig. 11. Query results showing test data
You should see three rows returned with the student data you inserted.
Clean up (optional)
If you want to remove the test table:
1
DROPTABLEstudents;
11. Android Emulator Setup (Host Machine)
The Android emulator runs on your host machine rather than inside the container. This provides
better performance and access to hardware acceleration.
Alternative: Android Studio
If you prefer a graphical interface for managing virtual devices, you can install
Android Studio instead of following the command-line approach below.
Android Studio includes the SDK Manager and AVD Manager with a GUI.
To make this setting persistent, add the export command to ~/.bashrc inside the container,
or add it to your devcontainer.json post-start command.
Verify the connection:
1
adb devices
You should see output similar to:
1
2
List of devices attached
emulator-5554 device
If the emulator appears in the list, you’re ready to deploy apps from the container.
12. Create and Run a MAUI Application
With the development container running and the emulator connected, you can create and deploy
a .NET MAUI application.
Create a new MAUI project
Inside the container terminal, create a new MAUI project:
1
2
cd /workspace
dotnet new maui -n HelloMaui
This creates a new directory called HelloMaui containing a default MAUI application with
a simple counter interface.
Build for Android
Navigate to the project directory and build for Android:
1
2
cd HelloMaui
dotnet build -f net9.0-android
Target Framework
The -f net9.0-android flag specifies the Android target framework. MAUI projects can
target multiple platforms (Android, iOS, Windows, Mac), and this flag ensures you build
specifically for Android.
The first build downloads additional dependencies and may take a few minutes. Subsequent
builds will be faster.
Deploy to the Emulator
Ensure your emulator is running and the ADB connection is established (check with adb devices),
then deploy and run the application:
1
dotnet build -f net9.0-android -t:Install
The -t:Install target builds the app and installs it on the connected emulator. After
installation completes, you can find the app in the emulator’s app drawer.
Alternatively, to build, install, and automatically launch the app:
1
dotnet build -f net9.0-android -t:Run
Warning
If the deployment fails with “no devices/emulators found”, verify that:
The emulator is running on your host machine
The ADB server is started with adb -a -P 5037 nodaemon server start on the host
The container has ADB_SERVER_SOCKET set correctly
adb devices shows the emulator in the container
Verify the Application
The default MAUI app displays a “Hello, World!” message and a button that counts clicks.
Tap the button to verify the app is running correctly.
Fig. 12. Default MAUI application running on the Android emulator
Hot Reload (Optional)
For faster development iteration, you can use Hot Reload to see changes without rebuilding:
1
dotnet watch run -f net9.0-android
Note
Hot Reload works best for XAML and minor code changes. Structural changes to your app
may still require a full rebuild.
13. Managing Your Development Environment
Starting and stopping
To stop the containers: Close VSCode or use the command palette (Ctrl+Shift+P / Cmd+Shift+P)
and select Dev Containers: Reopen Folder Locally.
You can also stop containers from the terminal:
1
docker compose down
To start the containers again: Open the project in VSCode and select
Dev Containers: Reopen in Container from the command palette.
Returning to local development
To switch back to developing outside the container, use the command palette and select
Dev Containers: Reopen Folder Locally. Your files remain on your local machine and are
always accessible.
Persistent data
The PostgreSQL data is stored in a Docker volume called postgres_data. This means your
database contents persist across container restarts. To completely reset the database, you
would need to remove this volume:
1
docker volume rm mauidevproject_postgres_data
Warning
Removing the volume deletes all data in the database. Only do this if you want to start fresh.
Rebuilding the container
If you need to update the development tools or modify the Dockerfile, rebuild the container:
Open the command palette (Ctrl+Shift+P / Cmd+Shift+P)
Select Dev Containers: Rebuild Container
This will rebuild the Docker image with any changes you’ve made to the Dockerfile.
Troubleshooting
Problem
Solution
Docker not running
Start Docker Desktop and wait for it to fully initialise
Port 5432 already in use
Stop any local PostgreSQL instance or change the port in docker-compose.yml
Container fails to start
Check Docker Desktop logs or run docker compose logs from the project directory
Cannot connect to database
Verify the containers are running with docker compose ps
Extensions not loading
Rebuild the container: Command Palette > Dev Containers: Rebuild Container
.NET SDK not found
Rebuild the container to ensure the Dockerfile completed successfully
ADB cannot connect to emulator
See the ADB troubleshooting section in the MAUI tutorial