Project Layout
Layout comparison
Section titled “Layout comparison”A TypeScript/Node project carries package.json, a build tool, a dist/ output folder, and node_modules. A Go project is simpler: go.mod declares the module and its dependencies; there is no separate build-output folder — go build produces a single binary.
// Express / NestJS project treemy-api/ package.json tsconfig.json src/ main.ts app.module.ts // NestJS root module books/ books.controller.ts books.service.ts books.dto.ts middleware/ logger.middleware.ts node_modules/// Echo project treebooks-api/ go.mod go.sum main.go // entry point; wire everything here internal/ handler/ books.go // HTTP handlers (parse, validate, call service) service/ books.go // business logic store/ books.go // database queries model/ book.go // shared structs / domain typesgo.mod — the package.json of Go
Section titled “go.mod — the package.json of Go”go.mod declares the module path (used as the import prefix) and the minimum Go version. go get adds dependencies; go mod tidy removes unused ones.
// package.json{ "name": "books-api", "version": "1.0.0", "dependencies": { "express": "^4.18.2" }, "devDependencies": { "typescript": "^5.0.0" }}// go.modmodule github.com/you/books-api
go 1.22
require ( github.com/labstack/echo/v4 v4.12.0)main.go — wiring the application
Section titled “main.go — wiring the application”In NestJS, main.ts calls NestFactory.create. In Echo, main.go calls echo.New(), registers middleware and routes, then calls e.Start. All wiring is explicit Go code — no decorators, no DI container.
// NestJS main.tsimport { NestFactory } from '@nestjs/core';import { AppModule } from './app.module';
async function bootstrap() { const app = await NestFactory.create(AppModule); app.setGlobalPrefix('api'); await app.listen(3000);}bootstrap();// main.gopackage main
import ( "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware"
"github.com/you/books-api/internal/handler" "github.com/you/books-api/internal/store")
func main() { e := echo.New()
// Middleware e.Use(middleware.Logger()) e.Use(middleware.Recover())
// Dependency wiring (manual, no container) bookStore := store.NewBookStore() bookHandler := handler.NewBookHandler(bookStore)
// Routes api := e.Group("/api") api.GET("/books", bookHandler.List) api.POST("/books", bookHandler.Create) api.GET("/books/:id", bookHandler.Get) api.PUT("/books/:id", bookHandler.Update) api.DELETE("/books/:id", bookHandler.Delete)
e.Logger.Fatal(e.Start(":1323"))}Run this locally — it needs the Echo module and a network port. From your project root:
go run main.go