Skip to content

Project Layout

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.

TypeScript
// Express / NestJS project tree
my-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/
Go
// Echo project tree
books-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 types

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.

TypeScript
// package.json
{
"name": "books-api",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
Go
// go.mod
module github.com/you/books-api
go 1.22
require (
github.com/labstack/echo/v4 v4.12.0
)

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.

TypeScript
// NestJS main.ts
import { 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();
Go
// main.go
package 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

What is the Go equivalent of package.json for declaring dependencies?
What does the internal/ directory enforce in Go?
Which command removes unused dependencies from go.mod?
In Echo, where does explicit route registration happen?