You're reading a sample of this book. Get the full version here.
Let's Go Further Getting Started › Project Setup and Skeleton Structure
Previous · Contents · Next
Chapter 2.1.

Project Setup and Skeleton Structure

Let’s kick things off by creating a greenlight directory to act as the top-level ‘home’ for this project. I’m going to create my project directory at $HOME/Projects/greenlight, but feel free to choose a different location if you wish.

$ mkdir -p $HOME/Projects/greenlight

Then change into this directory and use the go mod init command to enable modules for the project.

When running this command you’ll need to specify a module path, which is essentially a unique identifier for your project. In this book I’ll use greenlight.alexedwards.net as my module path, but if you’re following along you should ideally swap this for something that is unique to you instead.

$ cd $HOME/Projects/greenlight
$ go mod init greenlight.alexedwards.net
go: creating new go.mod: module greenlight.alexedwards.net

At this point you’ll see that a go.mod file has been created in the root of your project directory. If you open it up, it should look similar to this:

File: go.mod
module greenlight.alexedwards.net

go 1.23.0

We talked about modules in detail as part of the first Let’s Go book, but as a quick refresher let’s recap the main points here.

Generating the skeleton directory structure

Alright, now that our project directory has been created and we have a go.mod file, you can go ahead and run the following commands to generate a high-level skeleton structure for the project:

$ mkdir -p bin cmd/api internal migrations remote
$ touch Makefile
$ touch cmd/api/main.go

At this point your project directory should look exactly like this:

.
├── bin
├── cmd
│   └── api
│       └── main.go
├── internal
├── migrations
├── remote
├── go.mod
└── Makefile

Let’s take a moment to talk through these files and folders and explain the purpose that they’ll serve in our finished project.

It’s important to point out that the directory name internal carries a special meaning and behavior in Go: any packages which live under this directory can only be imported by code inside the parent of the internal directory. In our case, this means that any packages which live in internal can only be imported by code inside our greenlight project directory.

Or, looking at it the other way, this means that any packages under internal cannot be imported by code outside of our project.

This is useful because it prevents other codebases from importing and relying on the (potentially unversioned and unsupported) packages in our internal directory — even if the project code is publicly available somewhere like GitHub.

Hello world!

Before we continue, let’s quickly check that everything is setup correctly. Open the cmd/api/main.go file in your text editor and add the following code:

File: cmd/api/main.go
package main

import "fmt"

func main() {
    fmt.Println("Hello world!")
}

Save this file, then use the go run command in your terminal to compile and execute the code in the cmd/api package. All being well, you will see the following output:

$ go run ./cmd/api
Hello world!