Accessing Database from Deno Server-Side Application
Learning Objectives
- You know how to access a database from a Deno-based server-side application.
Here, we add a client to access the database from the Deno-based server-side application and modify the application to read data from the database.
Database client and setup
When working with databases, we need a database client that takes care of the communication with the database. In our case, we use Postgres.js.
Modify the deno.json file in the server folder to match the following.
{
"imports": {
"@hono/hono": "jsr:@hono/hono@4.8.12",
"postgres": "npm:postgres@3.4.7"
}
}
The above modification adds the Postgres.js client as a dependency to the server-side application, after which the dependency can be imported using import postgres from "postgres";. This allows us to create an instance of the database client and use it to make queries to the database.
The
npm:prefix is used to indicate that the dependency is from the npm registry. Deno supports importing dependencies from multiple registries.
Then, as the database client expects a certain format for the connection details, we need to modify the environment variables. Modify the project.env to match the following.
POSTGRES_USER=username
POSTGRES_PASSWORD=password
POSTGRES_DB=database
FLYWAY_USER=username
FLYWAY_PASSWORD=password
FLYWAY_URL=jdbc:postgresql://postgresql_database:5432/database
PGUSER=username
PGPASSWORD=password
PGDATABASE=database
PGHOST=postgresql_database
PGPORT=5432
The above modification adds the PG* environment variables that the Postgres.js client expects. Note that the PGHOST is set to the name of the database service defined in the compose.yaml, which is postgresql_database.
Finally, modify the compose.yaml configuration of the server service to match the following. The key changes are adding the depends_on directive to state that the server service depends on the database service and should be started after it, and the env_file directive to load the environment variables from the project.env file.
server:
build: server
restart: unless-stopped
volumes:
- ./server:/app
ports:
- 8000:8000
env_file:
- project.env
depends_on:
- database
With these changes, the server-side application has a driver for accessing the database service and the necessary environment variables needed to actually connect to the database.
Accessing database from server-side application
To access the database from the server-side application, we need to create an instance of the database client and use it to make queries to the database.
Let’s modify the server-side application to import the database client and to make an instance of it, and then add an endpoint that retrieves todos from the database. Modify the app.js to match the following.
import { Hono } from "@hono/hono";
import { cors } from "@hono/hono/cors";
import { logger } from "@hono/hono/logger";
// importing database client
import postgres from "postgres";
const app = new Hono();
// creating an instance of the database client
const sql = postgres();
app.use("/*", cors());
app.use("/*", logger());
let visits = 0;
app.get("/api/visits", (c) => {
visits++;
return c.json({ visits });
});
// retrieving todos from database on requests to /api/todos
app.get("/api/todos", async (c) => {
const todos = await sql`SELECT * FROM todos`;
return c.json(todos);
});
export default app;
Now, when we run docker compose up --build, we see that the project starts up. In addition, we can access the todos from the database by making a request to the server.
curl localhost:8000/api/todos
[]%
As there are no todos in the database, the response is an empty array.
We can access the database even though we did not provide the password in the code. This is because the Postgres.js client reads the connection details from the environment variables, which we set in the project.env file.
More specifically, Docker Compose loads the environment variables from the project.env file to the environment of the server service, and the Postgres.js client reads the connection details from there.
Adding data to the database
Let’s visit the database through the command line and add a todo.
docker exec -it postgresql_database psql -U username database
psql (17.5 (Debian 17.5-1.pgdg120+1))
Type "help" for help.
database=# INSERT INTO todos (name) VALUES ('Finish walking skeleton');
INSERT 0 1
database=# \q
Now, when we make a request to the server, we see the todo in the response.
curl localhost:8000/api/todos
[{"id":1,"name":"Finish walking skeleton","created_at":"2025-08-02T09:10:39.835Z"}]%
Summary
In summary:
- We added a database client to the Deno-based server-side application.
- We modified the server-side application to access the database and retrieve data from it.
- We added data to the database and verified that the server-side application can access it.
The file structure of the walking skeleton did not change. However, the server-side application now has the functionality for accessing the database.