Docs Project Layout

Project Layout

A common mistake when starting a new service is either:

  • Not thinking about structure at all
  • Or over-engineering structure before understanding the problem

Plumego encourages a third approach:

Start with a small, explicit layout that can evolve naturally.

This document introduces a minimal but disciplined project structure for Plumego applications.


After creating a minimal server, your project can start with the following structure:

plumego-demo/
β”œβ”€β”€ go.mod
β”œβ”€β”€ main.go
└── internal/
    └── app/
        └── app.go

This is enough to support:

  • A clear entry point
  • Application wiring
  • Future growth without refactoring

Why This Layout Works

This layout intentionally separates:

  • Process entry (main.go)
  • Application construction (internal/app)
  • Future domain and infrastructure code

It avoids:

  • Premature layering
  • Overly generic folder names
  • Framework-specific leakage into business code

main.go: The Process Boundary

Your main.go should remain small.

Its responsibilities are limited to:

  • Bootstrapping configuration
  • Creating the application
  • Starting the server
  • Handling process-level concerns

Example:

package main

import "example.com/plumego-demo/internal/app"

func main() {
	app.Run()
}

The goal is for main.go to remain boring.


internal/app: Application Wiring

The internal/app package is responsible for:

  • Creating the Plumego application
  • Registering routes
  • Attaching middleware
  • Returning a runnable server

Example internal/app/app.go:

package app

import (
	"net/http"

	"github.com/spcent/plumego"
)

func Run() {
	app := plumego.New()

	app.GET("/", func(ctx *plumego.Context) {
		ctx.String(http.StatusOK, "Hello, Plumego")
	})

	if err := app.Run(":8080"); err != nil {
		panic(err)
	}
}

This keeps Plumego usage contained and visible.


Why internal/ Matters

Using Go’s internal/ directory:

  • Prevents accidental imports from other modules
  • Clearly signals application-private code
  • Enforces architectural boundaries at the compiler level

This aligns well with Plumego’s emphasis on explicit boundaries.


What Not to Add Yet

At this stage, avoid introducing:

  • pkg/ directories
  • service/, controller/, handler/ splits
  • Complex configuration systems
  • Dependency injection frameworks

These structures make sense only after real complexity appears.


Growing the Layout Gradually

As your application grows, the structure can evolve naturally.

A common next step:

internal/
β”œβ”€β”€ app/
β”œβ”€β”€ http/
β”‚   β”œβ”€β”€ handler/
β”‚   └── middleware/
└── domain/

But do not start here unless you need to.

Plumego does not require a fixed layout β€”
it encourages layouts that reflect real boundaries.


Layout Principles to Keep in Mind

Regardless of structure, Plumego encourages:

  • Framework code at the edges
  • Domain logic isolated from HTTP
  • Explicit wiring over auto-discovery
  • Fewer, clearer directories over many vague ones

These principles matter more than any specific tree.


Common Anti-Patterns

Avoid the following early on:

  • Copying a β€œstandard layout” without understanding it
  • Mirroring framework internals in your project
  • Creating directories for concepts you do not yet have
  • Mixing domain logic into handlers

Structure should follow understanding, not templates.


Summary

A good Plumego project layout is:

  • Small at the beginning
  • Explicit in responsibility
  • Easy to evolve
  • Resistant to accidental complexity

Start simple.
Let structure emerge from real needs.


Next

Now that you have:

  • A running server
  • A minimal project layout

The next step is to understand how requests move through the system.

Continue with:

β†’ Concepts / Request Lifecycle

Or, if you prefer to complete the Getting Started flow:

β†’ Getting Started / First Request