{
  "slug": "Building-Modular-Go-Services-with-Uber-FX-and-SQLC-b8feb4b37721",
  "title": "🛠️ Building Modular Go Services with Uber FX and SQLC",
  "subtitle": "In the journey toward scalable, maintainable Go applications, few things matter more than clean architecture, lifecycle clarity, and…",
  "excerpt": "In the journey toward scalable, maintainable Go applications, few things matter more than clean architecture, lifecycle clarity, and…",
  "date": "2025-09-27",
  "tags": [
    "Go",
    "Architecture",
    "Machine Learning"
  ],
  "readingTime": "2 min",
  "url": "https://medium.com/@mobinshaterian/%EF%B8%8F-building-modular-go-services-with-uber-fx-and-sqlc-b8feb4b37721",
  "hero": "https://cdn-images-1.medium.com/max/800/1*DFfH9IUvng0kAxUTw3zbTQ.png",
  "content": [
    {
      "type": "heading",
      "level": 2,
      "text": "🛠️ Building Modular Go Services with Uber FX and SQLC"
    },
    {
      "type": "paragraph",
      "html": "In the journey toward scalable, maintainable Go applications, few things matter more than clean architecture, lifecycle clarity, and domain-driven modularity. <code>go-simple</code> project exemplifies this evolution, transforming a basic Gin + Uber FX setup into a robust, idiomatic service with SQLC-backed persistence and domain-centric layering."
    },
    {
      "type": "paragraph",
      "html": "This article walks through the architectural decisions and implementation strategies that shaped the <code>product</code> module in, based on the commit."
    },
    {
      "type": "paragraph",
      "html": "In the previous article, we converted the entire project to Uber FX, thereby improving its modularity and making dependency management more systematic."
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*DFfH9IUvng0kAxUTw3zbTQ.png",
      "alt": "🛠️ Building Modular Go Services with Uber FX and SQLC",
      "caption": "",
      "width": 1024,
      "height": 1024
    },
    {
      "type": "heading",
      "level": 2,
      "text": "🧱 Domain-Centric Structure: Why It Matters"
    },
    {
      "type": "paragraph",
      "html": "Rather than scattering controllers, services, and repositories across layer-centric folders, Mobin chose a domain-centric layout:"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "internal/\n└── product/    \n├── controller/    \n├── service/    \n├── repository/    \n└── module.go"
    },
    {
      "type": "paragraph",
      "html": "This structure encapsulates all business logic <code>product</code> in one place, making it easier to scale, test, and onboard new contributors."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "⚙️ SQLC Integration: Declarative, Type-Safe Persistence"
    },
    {
      "type": "paragraph",
      "html": "SQLC was introduced to generate type-safe Go code from raw SQL queries. The schema and query files live under:"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "internal/db/sqlc/\n├── schema/\n│   \n└── schema.sql\n├── queries/\n│   \n└── product.sql"
    },
    {
      "type": "paragraph",
      "html": "The schema defines the <code>products</code> table, while the queries cover full CRUD operations. SQLC generates Go bindings that are injected into the repository layer."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "🚀 Lifecycle-Driven Migrations"
    },
    {
      "type": "paragraph",
      "html": "To ensure the database schema is applied before the server starts, Mobin integrated <code>golang-migrate</code> into the FX lifecycle:"
    },
    {
      "type": "code",
      "lang": "go",
      "code": "fx.Invoke(migrate.RunMigrations)"
    },
    {
      "type": "paragraph",
      "html": "This guarantees that migrations run automatically on startup, keeping the database in sync with the codebase."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "🔌 Final Composition in main.go"
    },
    {
      "type": "paragraph",
      "html": "The <code>NewApp()</code> function brings it all together:"
    },
    {
      "type": "code",
      "lang": "go",
      "code": "func NewApp() *fx.App {\n    return fx.New(fx.Provide(config.NewConfig, health.New, server.NewGinEngine,\n    server.CreateHTTPServer, migrate.NewRunner, // ← migration runner),\n    fx.Invoke(server.RegisterRoutes, server.StartHTTPServer, migrate.RunMigrations, // ← migration\n    hook),)\n}"
    },
    {
      "type": "paragraph",
      "html": "This setup ensures that configuration, migrations, server startup, and domain modules are all orchestrated predictably."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Docker compose file"
    },
    {
      "type": "code",
      "lang": "yaml",
      "code": "services:\n  redis:\n    image: redis:alpine\n    ports:\n      - \"6379:6379\"\n    volumes:\n      - redis-data:/data\n    restart: unless-stopped\n  postgres:\n    image: postgres:latest\n    environment:\n      - POSTGRES_USER=user\n      - POSTGRES_PASSWORD=pass\n      - POSTGRES_DB=database\n    volumes:\n      - postgres-data:/var/lib/postgresql/data\n    ports:\n      - \"5432:5432\"\n    restart: unless-stoppedvolumes:\n  redis-data:\n  postgres-data:"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "🧠 Lessons from the Refactor"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<strong>Domain-centric design</strong> improves modularity and clarity.",
        "<strong>Uber FX</strong> simplifies dependency injection and lifecycle management.",
        "<strong>SQLC</strong> brings type safety and performance to database access.",
        "<strong>Docker + Postgres + Redis</strong> provide a clean dev environment.",
        "<strong>Migrations in FX</strong> ensure schema consistency without manual steps."
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "🧩 Conclusion"
    },
    {
      "type": "paragraph",
      "html": "The evolution of <code>go-simple</code> from a basic Gin server into a modular, lifecycle-driven architecture reflects a deeper commitment to clarity, reliability, and idiomatic Go design. By embracing domain-centric structure, SQLC for type-safe persistence, and Uber FX for dependency injection and lifecycle orchestration."
    },
    {
      "type": "paragraph",
      "html": "This refactor isn’t just about cleaner code — it’s about building systems that think in terms of domains, evolve gracefully, and stay predictable under pressure. Whether you’re adding new modules, integrating middleware, or preparing for production, the patterns established here offer a blueprint for thoughtful Go development."
    },
    {
      "type": "paragraph",
      "html": "As <code>go-simple</code> continues to grow, it stands as a testament to architectural discipline and the power of iterative refinement. The journey from simplicity to elegance has only just begun."
    },
    {
      "type": "paragraph",
      "html": "Your Business — On AutoPilot with <em>DDImedia AI Assistant</em><br>(<a href=\"https://waitlist.ddimedia.ai/join-the-waitlist-aie\" target=\"_blank\" rel=\"noreferrer noopener\">Join Our Waitlist</a>)"
    },
    {
      "type": "paragraph",
      "html": "Visit us at <a href=\"https://www.datadriveninvestor.com/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>DataDrivenInvestor.com</em></a>"
    },
    {
      "type": "paragraph",
      "html": "Join our creator ecosystem <a href=\"https://join.datadriveninvestor.com/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>here</em></a>."
    },
    {
      "type": "paragraph",
      "html": "DDI Official Telegram Channel: <a href=\"https://t.me/+tafUp6ecEys4YjQ1\" target=\"_blank\" rel=\"noreferrer noopener\">https://t.me/+tafUp6ecEys4YjQ1</a>"
    },
    {
      "type": "paragraph",
      "html": "Follow us on <a href=\"https://www.linkedin.com/company/data-driven-investor\" target=\"_blank\" rel=\"noreferrer noopener\"><em>LinkedIn</em></a>, <a href=\"https://twitter.com/@DDInvestorHQ\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Twitter</em></a>, <a href=\"https://www.youtube.com/c/datadriveninvestor\" target=\"_blank\" rel=\"noreferrer noopener\"><em>YouTube</em></a>, and <a href=\"https://www.facebook.com/datadriveninvestor\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Facebook</em></a>."
    }
  ]
}
