# Core Nx Tutorial - Step 2: Create Go CLI Great! you now have a simple blog set up. Next, you're going to create a CLI written in Go. ## Install Go Locally Make sure you have Go installed locally by following [these instructions](https://go.dev/doc/install). You can verify that Go is installed correctly by running: ```shell go version ``` ## Create the CLI Project Create a `project.json` file for your Go CLI. `packages/cli/project.json`: ```json { "root": "packages/cli", "sourceRoot": "packages/cli/src", "projectType": "application", "targets": { "build": { "executor": "nx:run-commands", "options": { "command": "go build -o='../../dist/packages/cli/' ./src/ascii.go", "cwd": "packages/cli" } }, "serve": { "executor": "nx:run-commands", "options": { "command": "go run ./src/ascii.go", "cwd": "packages/cli" } } } } ``` You could have the exact same functionality with a `package.json` file with a `scripts` section like this: ```json { "scripts": { "build": "go build -o='../../dist/packages/cli/' ./src/ascii.go", "serve": "go run ./src/ascii.˙go" } } ``` There are a few reasons to choose `project.json` for the CLI project. 1. The presence of `package.json` might cause other developers to think there is javascript code in this project. 2. As the scripts in the project get more complex, `project.json` tends to have a flatter structure - rather than a long horizontal line in `package.json` with all the cli flags. 3. The easiest method to run scripts provided in Nx plugins is to use a `project.json` file. All of these reasons are matters of preference. After this tutorial, you should have enough of a taste of both styles to make an informed decision about which format you prefer. Read more about [project configuration](/reference/project-configuration). ### Project.json syntax - `root`, `sourceRoot` and `application` are properties that help Nx know more about your project. - `targets` is similar to the `scripts` property in `package.json`. - Just as in `package.json`, `build` and `serve` can be any string you pick. - The `executor` is the code that runs the target. In this case, [`run-commands`](https://nx.dev/packages/nx/executors/run-commands) launches a terminal process to execute whatever command you pass in. - `options` contains whatever configuration properties the executor needs to run. ## Create the CLI This CLI will display some ASCII art in the terminal. Create the following files: `packages/cli/src/ascii.go`: ```go package main import ( "fmt" "os" ) func check(e error) { if e != nil { panic(e) } } func main() { fmt.Println("Hello, World!") dat, err := os.ReadFile("src/cow.txt") check(err) fmt.Print(string(dat)) } ``` `packages/cli/src/cow.txt`: ```shell _____ < moo > ----- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || ``` ## Run the CLI Now if you run `nx serve cli`, you'll see a friendly message: ```shell ❯ nx serve cli > nx run cli:serve > cli@ serve /Users/isaac/Documents/code/myorg/packages/cli > go run ./src/ascii.go Hello, World! _____ < moo > ----- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || ————————————————————————————————————————————————————————————————————————————————————————— > NX Successfully ran target serve for project cli (2s) See Nx Cloud run details at https://nx.app/runs/THRW7SDRL9S ``` Nx only caches the targets that you tell it to cache. `serve` is not in the default list of cached targets, so running this command a second time will take the same amount of time. You can see the current list of `cacheableOperations` in `nx.json`. ```json { //... "cacheableOperations": ["build", "lint", "test", "e2e"] } ``` If you run `nx build cli` twice, you'll see that Nx is able to cache the commands even though they're entirely written in Go. ## What's Next - Continue to [Step 3: Share assets](/core-tutorial/03-share-assets)