<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Shobhit Bhatnagar</title>
    <description>The latest articles on Forem by Shobhit Bhatnagar (@sbshobhit).</description>
    <link>https://forem.com/sbshobhit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3524249%2Fff26cfa5-e573-454f-adef-c254baeeb5a2.jpg</url>
      <title>Forem: Shobhit Bhatnagar</title>
      <link>https://forem.com/sbshobhit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sbshobhit"/>
    <language>en</language>
    <item>
      <title>Understanding Django, Gunicorn, and Database Connections</title>
      <dc:creator>Shobhit Bhatnagar</dc:creator>
      <pubDate>Thu, 16 Oct 2025 10:29:31 +0000</pubDate>
      <link>https://forem.com/sbshobhit/understanding-django-gunicorn-and-database-connections-5g50</link>
      <guid>https://forem.com/sbshobhit/understanding-django-gunicorn-and-database-connections-5g50</guid>
      <description>&lt;p&gt;Today, I was investigating an error that drew my attention to Gunicorn workers and Django database connections. I realized this is an important topic for anyone building scalable Django applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gunicorn Workers and Django Connections
&lt;/h3&gt;

&lt;p&gt;Let's clarify a common misconception: each Gunicorn worker is a forked process of the master. This means the Django CONN_MAX_AGE parameter applies independently within each worker process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CONN_MAX_AGE = 0 → A new database connection is created and dropped for every request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CONN_MAX_AGE = None → Connections are kept open indefinitely, allowing Django to reuse them across all requests handled by that worker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CONN_MAX_AGE &amp;gt; 0 → Connections are reused by the worker for the specified time (in seconds) and dropped after the timeout.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Important: Workers do not share database connections. Each worker maintains its own connection(s) based on CONN_MAX_AGE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjydpwpaqz6ir4rw5cdys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjydpwpaqz6ir4rw5cdys.png" alt=" " width="572" height="562"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Ideal Configuration by Traffic
&lt;/h3&gt;

&lt;p&gt;Case 1: Low Traffic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CONN_MAX_AGE = 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behavior: Each worker creates and drops connections per request.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal number of DB connections&lt;/li&gt;
&lt;li&gt;Fresh connection for each request&lt;/li&gt;
&lt;li&gt;Works well for low-traffic or development environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance overhead due to frequent connection creation&lt;/li&gt;
&lt;li&gt;Increased network traffic&lt;/li&gt;
&lt;li&gt;Scalability issues under higher load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Case 2: Medium/High Traffic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CONN_MAX_AGE ≈ 600 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behavior: Each worker maintains its connections for 10 minutes, creating new ones only after the timeout.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced latency&lt;/li&gt;
&lt;li&gt;Lower database overhead&lt;/li&gt;
&lt;li&gt;Better connection management&lt;/li&gt;
&lt;li&gt;Increased application resilience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slightly higher memory/resource consumption per worker&lt;/li&gt;
&lt;li&gt;Configuration complexity&lt;/li&gt;
&lt;li&gt;Less effective on very low-traffic sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Case 3: Very High Traffic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CONN_MAX_AGE = None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behavior: Connections are kept open indefinitely. Workers do not create/destroy connections per request.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced overhead on DB server&lt;/li&gt;
&lt;li&gt;Improved performance&lt;/li&gt;
&lt;li&gt;Efficient resource usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Risk of deadlocks or long-held locks if not managed properly&lt;/li&gt;
&lt;li&gt;Scalability challenges if worker count increases significantly&lt;/li&gt;
&lt;li&gt;Requires careful handling in ASGI or async contexts&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Worker Example
&lt;/h3&gt;

&lt;p&gt;Suppose you have 2 Gunicorn workers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Case 1: Each worker can have 1 active connection per request, frequently changing based on incoming requests.&lt;/li&gt;
&lt;li&gt;Case 2: Each worker maintains 1 persistent connection per worker, refreshed every CONN_MAX_AGE seconds.&lt;/li&gt;
&lt;li&gt;Case 3: Each worker maintains 1 persistent connection indefinitely, minimizing connection churn.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Common Misconception: More Workers = Better Performance
&lt;/h3&gt;

&lt;p&gt;It is a myth that increasing the number of Gunicorn workers automatically improves performance. In reality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More workers share the same CPU and memory resources, so each worker is still limited by the host's capacity.&lt;/li&gt;
&lt;li&gt;Instead of increasing worker count, it's recommended to increase the number of running containers. This reduces per-container overhead and allows horizontal scaling, which is far more effective in real-world production environments.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The Worker Formula and Its Practical Pitfall
&lt;/h3&gt;

&lt;p&gt;You may have heard the formula for calculating the number of workers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Number of workers = 2 × N + 1
where N is the number of CPU cores.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if your system has 8 vCPUs, you might assume you can safely run 17 workers.&lt;br&gt;
But in real life, you shouldn't.&lt;/p&gt;

&lt;p&gt;Instead of maxing out a single large instance, it's better to use multiple smaller instances - for example, servers with 1–2 vCPUs running 3–5 workers each.&lt;br&gt;
If the load grows, scale horizontally by adding more containers or instances, rather than vertically increasing CPU and RAM on one machine.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why You Should Avoid Vertical Scaling ?
&lt;/h3&gt;

&lt;p&gt;Vertical scaling (increasing CPU/memory on a single host) has several drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's expensive — larger instances cost disproportionately more.&lt;/li&gt;
&lt;li&gt;Even with more CPU and memory, you can still be bottlenecked at the network layer.&lt;/li&gt;
&lt;li&gt;Network saturation often limits how many database connections or DNS resolutions can occur simultaneously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my recent investigation, we were using a high number of workers with CONN_MAX_AGE = 0, and encountered DNS resolution errors for the database hostname (DB host name not resolved).&lt;br&gt;
The issue wasn't with the database or Django — it was due to network-level bottlenecks caused by too many workers constantly opening and closing connections.&lt;/p&gt;

&lt;p&gt;After reducing the number of workers, the system stabilized and handled high load efficiently, even with the same configuration aside from CONN_MAX_AGE.&lt;/p&gt;




&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use connection pooling tools like PgBouncer or AWS RDS Proxy. These handle connection management externally, improving scalability and reducing the overhead on your microservices.&lt;/li&gt;
&lt;li&gt;Fine-tune CONN_MAX_AGE based on traffic patterns and worker count.&lt;/li&gt;
&lt;li&gt;Monitor Gunicorn worker memory and connection usage to avoid unexpected bottlenecks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  References &amp;amp; Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/rds/proxy/" rel="noopener noreferrer"&gt;RDS Proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pgbouncer.org/" rel="noopener noreferrer"&gt;PgBouncer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.djangoproject.com/en/5.2/ref/settings/#std-setting-CONN_MAX_AGE" rel="noopener noreferrer"&gt;Django Database Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gunicorn.org/en/latest/design.html#how-many-workers" rel="noopener noreferrer"&gt;Gunicorn Worker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>django</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>Automate Your Go Project: Best Practices &amp; CI/CD with GitHub Actions</title>
      <dc:creator>Shobhit Bhatnagar</dc:creator>
      <pubDate>Sun, 05 Oct 2025 14:42:12 +0000</pubDate>
      <link>https://forem.com/sbshobhit/automate-your-go-project-best-practices-cicd-with-github-actions-4bo4</link>
      <guid>https://forem.com/sbshobhit/automate-your-go-project-best-practices-cicd-with-github-actions-4bo4</guid>
      <description>&lt;p&gt;You've built something cool in Go (Golang) — maybe a library, a CLI tool, or an API.&lt;br&gt;
Now you want to take it to the next level: package it properly and publish it so others can use it.&lt;/p&gt;

&lt;p&gt;That's where Continuous Integration and Continuous Deployment (CI/CD) comes in. It takes your local code and turns it into a repeatable, automated release pipeline, making your Go project reliable and easy to maintain.&lt;/p&gt;

&lt;p&gt;In this post, I'll walk you through how to build, test, and publish a Go package using GitHub Actions. We'll also use semantic versioning, linting, and a few good practices that help keep your releases clean and consistent.&lt;/p&gt;
&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;



&lt;p&gt;Before we start, it'll help if you're already familiar with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basics of the Go programming language &lt;/li&gt;
&lt;li&gt;How GitHub Actions work&lt;/li&gt;
&lt;li&gt;What semantic versioning (semver) and semantic releases mean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of this guide, you'll have a good understanding of how to automate the release process for your Go projects — the same way most open-source Go libraries are maintained.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building a CI/CD-Ready Go Package
&lt;/h2&gt;



&lt;p&gt;Here's a simple checklist before setting up automation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd7boisl0rk5em86asnm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd7boisl0rk5em86asnm.png" alt=" " width="720" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Code &amp;amp; Repo Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with solving a real problem. &lt;/li&gt;
&lt;li&gt;Keep your project clean and organized - &lt;a href="https://github.com/ticatwolves/go-project-skeleton" rel="noopener noreferrer"&gt;Take ref from here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;    &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Document everything clearly&lt;/li&gt;
&lt;li&gt;What your package does - Mostly in README and in comments &lt;/li&gt;
&lt;li&gt;How to install and use it - Mostly in README&lt;/li&gt;
&lt;li&gt;Always add examples of How to use - Mostly in README and in comments&lt;/li&gt;
&lt;li&gt;Go docs auto creates docs using comments that are written in your code&lt;/li&gt;
&lt;li&gt;In addition, You can also create a doc.go in each package that can contains the docs &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Linting &amp;amp; Formatting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before pushing changes, always format and lint your code&lt;/li&gt;
&lt;li&gt;Use githooks like precommit for auto linting and formatting on commits&lt;/li&gt;
&lt;li&gt;Or you can manually do it like
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Here we have used ./... to work on every go file in ./ directory
go fmt ./...   // Here fmt is used to format all the go files that are avaliable

go vet ./...   // Here vet examines your code and reports suspicious constructs
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;It's a small step that saves you from bigger code review headaches later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named your test files as *_test.go &lt;/li&gt;
&lt;li&gt;Test your code before every commit using

&lt;code&gt;go test ./...&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build your module locally to make sure everything compiles go build ./... &lt;/li&gt;
&lt;li&gt;This also helps confirm your code is production-ready before tagging a release.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Release&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once linting ✅, testing ✅, and building ✅ are done — you're ready to release.
In a CI/CD setup, releases are usually automated with semantic tags like v1.0.0.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Setting Up the Repository
&lt;/h2&gt;

&lt;p&gt;Let's get hands-on.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create and initialize your repository:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir &amp;lt;YOUR_PROJECT_NAME&amp;gt;
git init
mkdir src
cd src
go mod init github.com/&amp;lt;YOUR_USERNAME&amp;gt;/&amp;lt;YOUR_PROJECT_NAME&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, create your folder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/workflows/*.yaml    // GitHub actions workflow configurations
.config/goreleaser.yaml     // GoReleaser configuration
src/
  cmd/
    main.go // entry point of your project
    doc.go  // package documentation
    main_test.go  // test cases for your code
  go.mod    // Your Go mod file contains module name, go version and packages you are using
README.md   // Documentation about repository i.e. your project 
LICENSE     // Optional if you want to add a LICENSE
.gitignore  // contains pattern and files that will be ignored by git
.pre-commit-config.yaml // pre-commit configuration and hooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you'd like to skip setup, you can clone my sample repository: &lt;code&gt;github.com/ticatwolves/go-project-skeleton&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating Build, Test, and Release with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Here's where GitHub Actions works.&lt;br&gt;
You can automate almost everything — formatting, testing, tagging, and even publishing.&lt;/p&gt;

&lt;p&gt;A typical workflow includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running go fmt, go vet, and go test on every pull request&lt;/li&gt;
&lt;li&gt;Automatically tagging releases with semantic versions&lt;/li&gt;
&lt;li&gt;Building the package and pushing it to the Go proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple and easy to adapt workflow for each pull request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Lint &amp;amp; Format

on:
  pull_request:
    branches:
      - main

# Grant the jobs required permissions for OIDC to work
permissions:
  id-token: write
  contents: write
  pull-requests: write

jobs:
  Linter:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23
      - name: Install dependencies
        working-directory: ./src
        run: go mod tidy
      - name: Run go fmt
        working-directory: ./src
        run: go fmt ./...
      - name: Run go vet
        working-directory: ./src
        run: go vet ./...          
      - name: Update pull request
        uses: peter-evans/create-pull-request@v7
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "chore: format code"
          title: "[AUTO] Format code"
          body: "This PR automatically formats the code."
          branch: ${{ github.head_ref }}
          base: ${{ github.base_ref }}
          labels: |
            automated pr
  GoLangCI:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          # Required to report new issues on the PR
          fetch-depth: 0
      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@v8
        with:
          working-directory: ./src
  Test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23
      - name: Test
        working-directory: ./src
        run: go test -v ./...    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple and easy to adapt workflow for publishing changes to the package manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Release
on:
  push:
    branches: [ "main" ]
permissions:
  id-token: write
  contents: write
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23
      - name: Test
        working-directory: ./src
        run: go test -v ./...    
      - name: Go Semantic Release
        id: semrel
        uses: go-semantic-release/action@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Fetch tags created by semantic release
        if: steps.semrel.outputs.version != null &amp;amp;&amp;amp; steps.semrel.outputs.version != ''
        run: git fetch --tags

      - name: GoReleaser
        if: steps.semrel.outputs.version != null || steps.semrel.outputs.version != ''
        uses: goreleaser/goreleaser-action@v6
        with:
          distribution: goreleaser
          version: latest
          args: release --config .config/goreleaser.yaml --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above workflow we are using GoReleaser So here is the config file &lt;code&gt;goreleaser.yaml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: 2
builds:
  - dir: "./src"
    main: ./cmd/main.go
    env:
      - CGO_ENABLED=0
    goos:
      - linux
      - windows
      - darwin
    goarch:
      - amd64
      - arm64
release:
  github:
    owner: &amp;lt;YOUR_USERNAME&amp;gt;
    name: &amp;lt;YOUR_PROJECT_NAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Publishing on pkg.go.dev
&lt;/h2&gt;

&lt;p&gt;One last step — making your module discoverable.&lt;/p&gt;

&lt;p&gt;Go's official package discovery site, pkg.go.dev, doesn't automatically index new repos. After your first release (say, v1.0.0), visit: &lt;a href="https://pkg.go.dev/github.com/YOUR_USERNAME/YOUR_PROJECT_NAME" rel="noopener noreferrer"&gt;https://pkg.go.dev/github.com/YOUR_USERNAME/YOUR_PROJECT_NAME&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click “Request indexing” or “Fetch now” to get it listed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybrlq3hy67qter2j8lew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybrlq3hy67qter2j8lew.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once done, your package becomes publicly available for everyone to import:&lt;/p&gt;

&lt;p&gt;go get github.com/YOUR_USERNAME/&lt;a href="mailto:YOUR_REPO@v1.0.0"&gt;YOUR_REPO@v1.0.0&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Talk
&lt;/h2&gt;

&lt;p&gt;How do you handle CI/CD for your Go projects?&lt;br&gt;
Have you automated your release process yet, or are you still doing it manually?&lt;/p&gt;

&lt;p&gt;Drop your thoughts in the comments — I'd love to learn how others are approaching this!&lt;/p&gt;

&lt;h2&gt;
  
  
  References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ticatwolves/go-project-skeleton" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.dev/doc/tutorial/create-module" rel="noopener noreferrer"&gt;Go Modules Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goreleaser.com/" rel="noopener noreferrer"&gt;Publishing Go Modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://proxy.golang.org/" rel="noopener noreferrer"&gt;Proxy for Go Modules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cicd</category>
      <category>go</category>
      <category>githubactions</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building, Testing, and Publishing Go Packages - Best Practices</title>
      <dc:creator>Shobhit Bhatnagar</dc:creator>
      <pubDate>Thu, 02 Oct 2025 06:48:15 +0000</pubDate>
      <link>https://forem.com/sbshobhit/building-testing-and-publishing-go-packages-best-practices-8k</link>
      <guid>https://forem.com/sbshobhit/building-testing-and-publishing-go-packages-best-practices-8k</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/ticatwolves/shorten-url-service-with-go-and-aws-sam-24gn"&gt;previous article&lt;/a&gt;, we created a self-deployable Go-based URL Shortener Service and deployed it using AWS SAM.&lt;/p&gt;

&lt;p&gt;Now, let’s take things a step further by learning how to package and publish a Go module on the Golang package manager (&lt;a href="//pkg.go.dev"&gt;pkg.go.dev&lt;/a&gt;) so that it’s available for the open-source community. 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;We’ll use the shrinkIt module from my GitHub repository. You can clone it from here:&lt;br&gt;
👉 &lt;a href="https://github.com/ticatwolves/shrinkIt" rel="noopener noreferrer"&gt;ShrinkIt Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before publishing, let’s make sure the project is clean and production-ready.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Verify Dependencies
&lt;/h2&gt;

&lt;p&gt;Run the following command to clean up and verify module dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go mod tidy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures your go.mod and go.sum files are correct and only contain the dependencies you actually need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Run Tests
&lt;/h2&gt;

&lt;p&gt;Always test your module before publishing to ensure everything works as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your tests pass, you’re ready to move forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Commit Changes
&lt;/h2&gt;

&lt;p&gt;Use Conventional Commits when pushing changes. This helps with semantic versioning, which is crucial when publishing Go packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git commit -m "feat: add new feature" 
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Tag Your Release
&lt;/h2&gt;

&lt;p&gt;Now, assign a version tag to your commit. For example, version v0.1.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git tag v0.1.0
git push origin v0.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now see the tag under the Tags section in your remote Git repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Publish to the Go Package Manager
&lt;/h2&gt;

&lt;p&gt;Finally, publish your package to pkg.go.dev using the Go proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOPROXY=proxy.golang.org go list -m github.com/ticatwolves/shrinkit@v0.1.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Note: You can change the GOPROXY depending on whether you want to test or publish to the production package manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Use Your Package
&lt;/h2&gt;

&lt;p&gt;Once published, your package is available for anyone to use in their projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/ticatwolves/shrinkit@v0.1.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations 🎉 — you’ve published your first Go package to the public!&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;That's it for now! Join us in our next article, where we'll explore how to add a CI/CD pipeline for automated building, testing, and publishing of your Go packages.&lt;/p&gt;

&lt;p&gt;💬 How do you handle versioning and publishing in your Go projects? Share your workflow in the comments — I’d love to learn from your experience!&lt;/p&gt;

&lt;p&gt;📚 Further Reading &amp;amp; References&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://go.dev/doc/modules/" rel="noopener noreferrer"&gt;Go Modules Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;Semantic Version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://proxy.golang.org/" rel="noopener noreferrer"&gt;Proxy for Go Modules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>packaging</category>
      <category>programming</category>
    </item>
    <item>
      <title>Shorten URL Service with Go and AWS SAM</title>
      <dc:creator>Shobhit Bhatnagar</dc:creator>
      <pubDate>Sun, 28 Sep 2025 14:13:48 +0000</pubDate>
      <link>https://forem.com/sbshobhit/shorten-url-service-with-go-and-aws-sam-24gn</link>
      <guid>https://forem.com/sbshobhit/shorten-url-service-with-go-and-aws-sam-24gn</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/ticatwolves/golang-project-template-4iib"&gt;previous article&lt;/a&gt; I explained how to structure a Golang project for better readability and maintainability. &lt;/p&gt;

&lt;p&gt;Now, let’s take it a step further by building a URL Shortener Service using Go and AWS SAM (Serverless Application Model).🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  What is AWS SAM?
&lt;/h2&gt;

&lt;p&gt;SAM (Serverless Application Model) is an Infrastructure as Code (IaC) tool provided by AWS. It simplifies deploying serverless applications by letting you define them in a template and deploying via CloudFormation&lt;/p&gt;

&lt;h2&gt;
  
  
  Key advantages:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Easy deployment of serverless applications &lt;/li&gt;
&lt;li&gt;✅ Built-in support for AWS Lambda, API Gateway, DynamoDB, etc. &lt;/li&gt;
&lt;li&gt;✅ Package and publish apps to the AWS Serverless Application Repository &lt;/li&gt;
&lt;li&gt;✅ CI/CD friendly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Flow Diagram
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqirairptykhoh00t6waq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqirairptykhoh00t6waq.png" alt=" " width="403" height="109"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Flow
&lt;/h2&gt;

&lt;p&gt;Here’s how the URL shortener works under the hood:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client Request -&amp;gt; The user submits a request to API Gateway.&lt;/li&gt;
&lt;li&gt;Lambda Trigger -&amp;gt; API Gateway routes the request to a Lambda function written in Go.&lt;/li&gt;
&lt;li&gt;Supported Operations - POST, GET.&lt;/li&gt;
&lt;li&gt;POST Operations:

&lt;ul&gt;
&lt;li&gt;The Lambda Parse the request payload.&lt;/li&gt;
&lt;li&gt;The handler generates a hash of the original URL.&lt;/li&gt;
&lt;li&gt;The hash and actual URL are stored in the database (DynamoDB).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GET Operations:

&lt;ul&gt;
&lt;li&gt;It retrieves the original URL by using Hash in the request URL.&lt;/li&gt;
&lt;li&gt;Lambda returns an HTTP 302 redirect with the original URL in the Location header.&lt;/li&gt;
&lt;li&gt;Client browser follows the redirect and loads the original URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;I’ve open-sourced the complete implementation here:&lt;br&gt;
👉 &lt;a href="https://github.com/ticatwolves/shrinkI" rel="noopener noreferrer"&gt;ShrinkIt – URL Shortener with Go + SAM&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building and Deploying with SAM
&lt;/h2&gt;

&lt;p&gt;Step 1: Clone &lt;code&gt;git clone https://github.com/ticatwolves/shrinkIt.git&lt;/code&gt;&lt;br&gt;
Step 2: Build the Project &lt;code&gt;make build&lt;/code&gt;&lt;br&gt;
Step 3: Deploy the Project &lt;code&gt;make deploy&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Feel free to check it out, clone the repo, and try it yourself!&lt;/p&gt;

&lt;p&gt;💬 Have you tried building serverless applications with Go before? Share your experience in the comments — I’d love to hear your thoughts!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>serverless</category>
      <category>go</category>
      <category>sam</category>
    </item>
    <item>
      <title>GoLang Project Template</title>
      <dc:creator>Shobhit Bhatnagar</dc:creator>
      <pubDate>Tue, 23 Sep 2025 14:02:12 +0000</pubDate>
      <link>https://forem.com/sbshobhit/golang-project-template-4iib</link>
      <guid>https://forem.com/sbshobhit/golang-project-template-4iib</guid>
      <description>&lt;p&gt;Starting a journey with a new programming language is always challenging — and I've been there myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvydiiw2f7yha6lnrw9xg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvydiiw2f7yha6lnrw9xg.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I began learning Go (Golang) when I was comparing it with Python for some tasks deployed on AWS Lambda. The cold start time with Python was too high, so I started looking for alternatives. That’s when I discovered Golang.&lt;/p&gt;

&lt;p&gt;After learning the basics, the first big question I had was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the best way to structure a Go project?&lt;/li&gt;
&lt;li&gt;How do companies organize and maintain Golang repositories?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key Learnings About Go Project Setup&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every Go file must start with a package name.&lt;/li&gt;
&lt;li&gt;The package name doesn't need to match the file or folder name.&lt;/li&gt;
&lt;li&gt;A project's go version and module is defined in the go.mod file, which should always be in the root directory.&lt;/li&gt;
&lt;li&gt;The go.sum file is auto-generated when you run &lt;code&gt;go mod tidy&lt;/code&gt;. It records dependency versions to ensure reproducible builds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, you'll have a standalone executable binary file that can be published on the Go package manager or deployed (for example, on AWS Lambda).&lt;/p&gt;

&lt;p&gt;Clean Go Project Structure (Template)&lt;br&gt;
When building maintainable applications, following a clean and well-organized folder structure is essential. Here's a recommended Golang project structure you can use as a template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root
|
|- build/              # Packaging and CI/CD related files
|- cmd/                # Application entry point
|   └── main.go        # For single entry point
|   └── EntryPointA    # For multiple entry points
|        └── *.go 
|   └── EntryPointB    # For multiple entry points
|        └── *.go 
|- internal/           # Private application and library code(internal logic)
|   └── *.go           # write your business logic also we can split them into packages like api, database, auth, etc
|   └── packageA       # packageA code 
|        └── *.go
|   └── packageB       # packageB code
|        └── *.go
|- api/                # Add backend API
|   └── *.go
|   └── apiA           
|        └── *.go
|- pkg/                # Public utility functions and reusable code
|   └── *.go
|   └── util           # Add Util code like validator, generic code, 
etc.  
|        └── *.go
|- vendor/             # Add Vendor packages
|   └── packageName     
|- static/             # Static files (html, css, js, asset)
|   └── css            # CSS files 
|   └── js             # JS files
|   └── asset          # Other static files .png, .jpg etc  
|   └── templates      # HTML templates 
|- scripts/            # Automation and helper scripts
|- configs/            # Configuration files (YAML, JSON, TOML, etc.)
|- go.mod              # Module definition
|- go.sum              # Dependency lock file (auto-generated)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This folder layout is inspired by clean architecture principles and helps keep Go projects scalable, testable, and easier to collaborate on.&lt;/p&gt;

&lt;p&gt;Why Follow This Folder Structure?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improves readability and maintainability&lt;/li&gt;
&lt;li&gt;Supports clean architecture and modular code&lt;/li&gt;
&lt;li&gt;Makes it easy for new developers to understand the project&lt;/li&gt;
&lt;li&gt;Ensures scalable backend development with Go&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;If you're just starting with Golang, this template will give you a solid foundation for structuring your projects. Following a clean folder structure and using Go best practices ensures your applications are easier to maintain and scale.&lt;/p&gt;

&lt;p&gt;💬 What do you think of this Go project structure? Did I miss something important? Share your thoughts in the comments — I'd love to learn from your experience too!&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
