DEV Community

Cover image for Redoed #3: Connecting Go Server to PostgreSQL with GORM
Mahesh Odedara
Mahesh Odedara

Posted on • Originally published at heshify.github.io

Redoed #3: Connecting Go Server to PostgreSQL with GORM

Building Redoed : Connecting Go Server to PostgreSQL with GORM

Now that our Go server and PostgreSQL database are running inside Docker containers, it's time to integrate the database with the server. I’ll be using GORM, a popular ORM for Go. Writing raw SQL is always an option if we want to avoid dependencies, but I wanted to experiment with GORM for this project.

Installing Dependencies

Before we start writing the database logic, let's install the required dependencies:

go get -u gorm.io/gorm gorm.io/driver/postgres github.com/joho/godotenv github.com/google/uuid
Enter fullscreen mode Exit fullscreen mode

With these installed, we're ready to connect to PostgreSQL.

Setting Up the Database Package

To keep the codebase organized, database logic will live in its own package. Inside internal/db/db.go, we'll set up the connection.

Initializing the Database

The database package will manage the connection and keep it accessible across the application. First, we import the required packages:

package database

import (
  "fmt"
  "log"
  "os"

  "github.com/joho/godotenv"
  "gorm.io/driver/postgres"
  "gorm.io/gorm"
Enter fullscreen mode Exit fullscreen mode

This line declares a global DB variable that will hold the database connection:

var DB *gorm.DB
Enter fullscreen mode Exit fullscreen mode

Keeping it global makes it accessible throughout the app without needing to pass it around. It'll be assigned a connection inside InitDb(), so once Initialized, we can use DB for queries and migrations.

Loading Environment Variables

Now, let's write the function that initializes the database. First, we load the database credentials from the .env file:

func InitDb() {
  if err := godotenv.Load(); err != nil {
        log.Fatal("Error loading .env file")
    }
 //...
}
Enter fullscreen mode Exit fullscreen mode

If the .env file is missing, the application logs an error and exits, preventing it from running with missing credentials.

Constructing the Connection String

With the environment variables loaded, we can now construct the PostgreSQL connection string dynamically:

//...
    host := os.Getenv("DB_HOST")
    port := os.Getenv("DB_PORT")
    user := os.Getenv("DB_USER")
    password := os.Getenv("DB_PASSWORD")
    dbname := os.Getenv("DB_NAME")

    connectionStr := fmt.Sprintf(
        "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
        host, user, password, dbname, port,
    )
//...
Enter fullscreen mode Exit fullscreen mode

Here, we’re pulling values from the environment and constructing the connection string, which we’ll use to connect to the database.

Connecting to PostgreSQL

With the connection string ready, GORM provides a simple way to open a connection:

//...
    DB, err = gorm.Open(postgres.Open(connectionStr), &gorm.Config{})
    if err != nil {
        log.Fatalf("ERROR: Failed to initialize database: %v", err)
    }

    log.Println("INFO: Database initialized")
}
Enter fullscreen mode Exit fullscreen mode

The gorm.Open() function initializes the database connection. It takes postgres.Open(connectionStr) as the driver and a configuration struct. If the connection fails due to incorrect credentials or an unreachable database then the app logs the error and exits. Otherwise, we get a confirmation message, and the database is ready to use.

Connecting the Server to the Database

At this point, the database is set up, but the server doesn’t know about it yet. Let’s initialize the connection when the application starts.

Inside main.go, add:

func init() {
  db.InitDb()
}
Enter fullscreen mode Exit fullscreen mode

Now, every time the server runs, it ensures that the database is connected and ready to use.

Defining the Document Model

Now that the database is set up, let;s define the structure for documents.

Inside internal/models/document.go

package models

import (
    "time"

    "github.com/google/uuid"
)

type Document struct {
    ID        uuid.UUID `gorm:"type:uuid;default:gen_random_uuid();primaryKey"`
    Title     string    `json:"title"`
    Content   string    `json:"content"`
    CreatedAt time.Time
    UpdatedAt time.Time
}
Enter fullscreen mode Exit fullscreen mode

Each document will have a title and content along with a unique UUID as its primary key and timestamps to track creation and updates.

Running Migrations

We can create the documents table in the database using GORM’s AutoMigrate function. For now, let's add this line inside InitDb():

func InitDb() {
//...
DB.AutoMigrate(&models.Document{})
}
Enter fullscreen mode Exit fullscreen mode

This ensures that whenever the application starts, the database schema is up to date.

Now, if we run:

docker compose up --build
Enter fullscreen mode Exit fullscreen mode

It will build our Go code and start both server and database containers.

If there are no errors, we can check the document table inside psql by running \dt:

mydb-# \dt
         List of relations
 Schema |   Name    | Type  | Owner
--------+-----------+-------+-------
 public | documents | table | user
(1 row)
Enter fullscreen mode Exit fullscreen mode

Conclusion

With the datbase connected, we're now ready to start building the API.

See you in the next post!

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

While many AI coding tools operate as simple command-response systems, Qodo Gen 1.0 represents the next generation: autonomous, multi-step problem-solving agents that work alongside you.

Read full post

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay