Platform.sh User Documentation

Go

Upsun Beta

Access our newest offering - Upsun!

Get your free trial by clicking the link below.

Get your Upsun free trial

Platform.sh supports building and deploying applications written in Go using Go modules. They’re compiled during the Build hook phase, and support both committed dependencies and download-on-demand.

Supported versions Anchor to this heading

You can select the major and minor version.

Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches.

Grid Dedicated Gen 3 Dedicated Gen 2
  • 1.22
  • 1.21
  • 1.20
None available None available

Specify the language Anchor to this heading

To use Go, specify golang as your app’s type:

.platform.app.yaml
type: 'golang:<VERSION_NUMBER>'

For example:

.platform.app.yaml
type: 'golang:1.22'

Deprecated versions Anchor to this heading

The following versions are deprecated. They’re available, but they aren’t receiving security updates from upstream and aren’t guaranteed to work. They’ll be removed in the future, so migrate to one of the supported versions.

  • 1.19
  • 1.18
  • 1.17
  • 1.16
  • 1.15
  • 1.14
  • 1.13
  • 1.12
  • 1.11
  • 1.10
  • 1.9
  • 1.8

Go modules Anchor to this heading

The recommended way to handle Go dependencies on Platform.sh is using Go module support in Go 1.11 and later. That allows the build process to use go build directly without any extra steps, and you can specify an output executable file of your choice. (See the examples below.)

Building and running the application Anchor to this heading

Assuming your go.mod and go.sum files are present in your repository, your application can be built with the command go build, to produce a working executable. You can then start it from the web.commands.start directive. Note that the start command must run in the foreground. If the program terminates for any reason it is automatically restarted.

The following basic .platform.app.yaml file is sufficient to run most Go applications.

.platform.app.yaml
name: app

type: golang:1.14

hooks:
    build: |
        # Modify this line if you want to build differently or use an alternate name for your executable.
        go build -o bin/app        

web:
    upstream:
        socket_family: tcp
        protocol: http

    commands:
        # If you change the build output in the build hook above, update this line as well.
        start: ./bin/app

    locations:
        /:
            # Route all requests to the Go app, unconditionally.
            allow: false
            passthru: true

disk: 1024

Note that there is still an Nginx proxy server sitting in front of your application. If desired, certain paths may be served directly by Nginx without hitting your application (for static files, primarily) or you may route all requests to the Go application unconditionally, as in the example above.

Accessing services Anchor to this heading

To access various services with Go, see the following examples. The individual service pages have more information on configuring each service.

package examples

import (
	"fmt"
	"github.com/bradfitz/gomemcache/memcache"
	psh "github.com/platformsh/config-reader-go/v2"
	gomemcache "github.com/platformsh/config-reader-go/v2/gomemcache"
)

func UsageExampleMemcached() string {

	// Create a NewRuntimeConfig object to ease reading the Platform.sh environment variables.
	// You can alternatively use os.Getenv() yourself.
	config, err := psh.NewRuntimeConfig()
	checkErr(err)

	// Get the credentials to connect to the Solr service.
	credentials, err := config.Credentials("memcached")
	checkErr(err)

	// Retrieve formatted credentials for gomemcache.
	formatted, err := gomemcache.FormattedCredentials(credentials)
	checkErr(err)

	// Connect to Memcached.
	mc := memcache.New(formatted)

	// Set a value.
	key := "Deploy_day"
	value := "Friday"

	err = mc.Set(&memcache.Item{Key: key, Value: []byte(value)})

	// Read it back.
	test, err := mc.Get(key)

	return fmt.Sprintf("Found value <strong>%s</strong> for key <strong>%s</strong>.", test.Value, key)
}
package examples

import (
	"context"
	"fmt"
	psh "github.com/platformsh/config-reader-go/v2"
	mongoPsh "github.com/platformsh/config-reader-go/v2/mongo"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"time"
)

func UsageExampleMongoDB() string {

	// Create a NewRuntimeConfig object to ease reading the Platform.sh environment variables.
	// You can alternatively use os.Getenv() yourself.
	config, err := psh.NewRuntimeConfig()
	checkErr(err)

	// Get the credentials to connect to the Solr service.
	credentials, err := config.Credentials("mongodb")
	checkErr(err)

	// Retrieve the formatted credentials for mongo-driver.
	formatted, err := mongoPsh.FormattedCredentials(credentials)
	checkErr(err)

	// Connect to MongoDB using the formatted credentials.
	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
	client, err := mongo.Connect(ctx, options.Client().ApplyURI(formatted))
	checkErr(err)

	// Create a new collection.
	collection := client.Database("main").Collection("starwars")

	// Clean up after ourselves.
	err = collection.Drop(context.Background())
	checkErr(err)

	// Create an entry.
	res, err := collection.InsertOne(ctx, bson.M{"name": "Rey", "occupation": "Jedi"})
	checkErr(err)

	id := res.InsertedID

	// Read it back.
	cursor, err := collection.Find(context.Background(), bson.M{"_id": id})
	checkErr(err)

	var name string
	var occupation string

	for cursor.Next(context.Background()) {
		document := struct {
			Name       string
			Occupation string
		}{}
		err := cursor.Decode(&document)
		checkErr(err)

		name = document.Name
		occupation = document.Occupation
	}

	return fmt.Sprintf("Found %s (%s)", name, occupation)
}
package examples

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
	psh "github.com/platformsh/config-reader-go/v2"
	sqldsn "github.com/platformsh/config-reader-go/v2/sqldsn"
)

func UsageExampleMySQL() string {

	// Create a NewRuntimeConfig object to ease reading the Platform.sh environment variables.
	// You can alternatively use os.Getenv() yourself.
	config, err := psh.NewRuntimeConfig()
	checkErr(err)

	// The 'database' relationship is generally the name of the primary SQL database of an application.
	// That's not required, but much of our default automation code assumes it.
	credentials, err := config.Credentials("database")
	checkErr(err)

	// Using the sqldsn formatted credentials package.
	formatted, err := sqldsn.FormattedCredentials(credentials)
	checkErr(err)

	db, err := sql.Open("mysql", formatted)
	checkErr(err)

	defer db.Close()

	// Force MySQL into modern mode.
	db.Exec("SET NAMES=utf8")
	db.Exec("SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES," +
		"NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO," +
		"NO_AUTO_CREATE_USER,ONLY_FULL_GROUP_BY'")

	// Creating a table.
	sqlCreate := "CREATE TABLE IF NOT EXISTS People (" +
		"id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY," +
		"name VARCHAR(30) NOT NULL," +
		"city VARCHAR(30) NOT NULL)"

	_, err = db.Exec(sqlCreate)
	checkErr(err)

	// Insert data.
	sqlInsert := "INSERT INTO People (name, city) VALUES" +
		"('Neil Armstrong', 'Moon')," +
		"('Buzz Aldrin', 'Glen Ridge')," +
		"('Sally Ride', 'La Jolla');"

	_, err = db.Exec(sqlInsert)
	checkErr(err)

	table := "<table>" +
		"<thead>" +
		"<tr><th>Name</th><th>City</th></tr>" +
		"</thead>" +
		"<tbody>"

	var id int
	var name string
	var city string

	rows, err := db.Query("SELECT * FROM People")
	if err != nil {
		panic(err)
	} else {
		for rows.Next() {
			err = rows.Scan(&id, &name, &city)
			checkErr(err)
			table += fmt.Sprintf("<tr><td>%s</td><td>%s</td><tr>\n", name, city)
		}
		table += "</tbody>\n</table>\n"
	}

	_, err = db.Exec("DROP TABLE People;")
	checkErr(err)

	return table
}
package examples

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
	psh "github.com/platformsh/config-reader-go/v2"
	libpq "github.com/platformsh/config-reader-go/v2/libpq"
)

func UsageExamplePostgreSQL() string {

	// Create a NewRuntimeConfig object to ease reading the Platform.sh environment variables.
	// You can alternatively use os.Getenv() yourself.
	config, err := psh.NewRuntimeConfig()
	checkErr(err)

	// The 'database' relationship is generally the name of the primary SQL database of an application.
	// It could be anything, though, as in the case here where it's called "postgresql".
	credentials, err := config.Credentials("postgresql")
	checkErr(err)

	// Retrieve the formatted credentials.
	formatted, err := libpq.FormattedCredentials(credentials)
	checkErr(err)

	// Connect.
	db, err := sql.Open("postgres", formatted)
	checkErr(err)

	defer db.Close()

	// Creating a table.
	sqlCreate := "CREATE TABLE IF NOT EXISTS PeopleGo (" +
		"id SERIAL PRIMARY KEY," +
		"name VARCHAR(30) NOT NULL," +
		"city VARCHAR(30) NOT NULL);"

	_, err = db.Exec(sqlCreate)
	checkErr(err)

	// Insert data.
	sqlInsert := "INSERT INTO PeopleGo(name, city) VALUES" +
		"('Neil Armstrong', 'Moon')," +
		"('Buzz Aldrin', 'Glen Ridge')," +
		"('Sally Ride', 'La Jolla');"

	_, err = db.Exec(sqlInsert)
	checkErr(err)

	table := "<table>" +
		"<thead>" +
		"<tr><th>Name</th><th>City</th></tr>" +
		"</thead>" +
		"<tbody>"

	var id int
	var name string
	var city string

	// Read it back.
	rows, err := db.Query("SELECT * FROM PeopleGo")
	if err != nil {
		panic(err)
	} else {
		for rows.Next() {
			err = rows.Scan(&id, &name, &city)
			checkErr(err)
			table += fmt.Sprintf("<tr><td>%s</td><td>%s</td><tr>\n", name, city)
		}
		table += "</tbody>\n</table>\n"
	}

	_, err = db.Exec("DROP TABLE PeopleGo;")
	checkErr(err)

	return table
}
package examples

import (
	"fmt"
	psh "github.com/platformsh/config-reader-go/v2"
	amqpPsh "github.com/platformsh/config-reader-go/v2/amqp"
	"github.com/streadway/amqp"
	"sync"
)

func UsageExampleRabbitMQ() string {

	// Create a NewRuntimeConfig object to ease reading the Platform.sh environment variables.
	// You can alternatively use os.Getenv() yourself.
	config, err := psh.NewRuntimeConfig()
	checkErr(err)

	// Get the credentials to connect to RabbitMQ.
	credentials, err := config.Credentials("rabbitmq")
	checkErr(err)

	// Use the amqp formatted credentials package.
	formatted, err := amqpPsh.FormattedCredentials(credentials)
	checkErr(err)

	// Connect to the RabbitMQ server.
	connection, err := amqp.Dial(formatted)
	checkErr(err)
	defer connection.Close()

	// Make a channel.
	channel, err := connection.Channel()
	checkErr(err)
	defer channel.Close()

	// Create a queue.
	q, err := channel.QueueDeclare(
		"deploy_days", // name
		false,         // durable
		false,         // delete when unused
		false,         // exclusive
		false,         // no-wait
		nil,           // arguments
	)

	body := "Friday"
	msg := fmt.Sprintf("Deploying on %s", body)

	// Publish a message.
	err = channel.Publish(
		"",     // exchange
		q.Name, // routing key
		false,  // mandatory
		false,  // immediate
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(msg),
		})
	checkErr(err)

	outputMSG := fmt.Sprintf("[x] Sent '%s' <br>", body)

	// Consume the message.
	msgs, err := channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	checkErr(err)

	var received string
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		for d := range msgs {
			received = fmt.Sprintf("[x] Received message: '%s' <br>", d.Body)
			wg.Done()
		}
	}()

	wg.Wait()

	outputMSG += received

	return outputMSG
}
package examples

import (
	"fmt"

	psh "github.com/platformsh/config-reader-go/v2"
	gosolr "github.com/platformsh/config-reader-go/v2/gosolr"
	solr "github.com/rtt/Go-Solr"
)

func UsageExampleSolr() string {

	// Create a NewRuntimeConfig object to ease reading the Platform.sh environment variables.
	// You can alternatively use os.Getenv() yourself.
	config, err := psh.NewRuntimeConfig()
	checkErr(err)

	// Get the credentials to connect to the Solr service.
	credentials, err := config.Credentials("solr")
	checkErr(err)

	// Retrieve Solr formatted credentials.
	formatted, err := gosolr.FormattedCredentials(credentials)
	checkErr(err)

	// Connect to Solr using the formatted credentials.
	connection := &solr.Connection{URL: formatted}

	// Add a document and commit the operation.
	docAdd := map[string]interface{}{
		"add": []interface{}{
			map[string]interface{}{"id": 123, "name": "Valentina Tereshkova"},
		},
	}

	respAdd, err := connection.Update(docAdd, true)
	checkErr(err)

	// Select the document.
	q := &solr.Query{
		Params: solr.URLParamMap{
			"q": []string{"id:123"},
		},
	}

	resSelect, err := connection.CustomSelect(q, "query")
	checkErr(err)

	// Delete the document and commit the operation.
	docDelete := map[string]interface{}{
		"delete": map[string]interface{}{
			"id": 123,
		},
	}

	resDel, err := connection.Update(docDelete, true)
	checkErr(err)

	message := fmt.Sprintf("Adding one document - %s<br>"+
		"Selecting document (1 expected): %d<br>"+
		"Deleting document - %s<br>",
		respAdd, resSelect.Results.NumFound, resDel)

	return message
}

You can get all information about a deployed environment, including how to connect to services, through environment variables. Your app can access these variables.

You can also use the library to read other environment variables.

package main

import (
	_ "github.com/go-sql-driver/mysql"
	psh "github.com/platformsh/gohelper"
	"net/http"
)

func main() {

	p, err := psh.NewPlatformInfo()

	if err != nil {
		panic("Not in a Platform.sh Environment.")
	}

	http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
		// ...
	})

	http.ListenAndServe(":"+p.Port, nil)
}

Configuration reader Anchor to this heading

While you can read the environment directly from your app, you might want to use the Go configuration reader library. It decodes service credentials, the correct port, and other information for you.

Project templates Anchor to this heading

The following list shows templates available for Go apps.

A template is a starting point for building your project. It should help you get a project ready for production.

Beego

Beego

This template demonstrates building the Beego framework for Platform.sh using Go modules. It includes a minimalist application skeleton that demonstrates how to connect to a MariaDB server. It is intended for you to use as a starting point and modify for your own needs.

Beego is a popular web framework written in Go.

Features:

  • Go 1.14
  • MariaDB 10.4
  • Automatic TLS certificates
  • Git module-based build

View the repository on GitHub.

Echo

Echo

This template demonstrates building the Echo framework for Platform.sh using Go modules. It includes a minimalist application skeleton that demonstrates how to connect to a MariaDB server. It is intended for you to use as a starting point and modify for your own needs.

Echo is a lightweight, minimalist web framework written in Go.

Features:

  • Go 1.14
  • MariaDB 10.4
  • Automatic TLS certificates
  • Git module-based build

View the repository on GitHub.

Gin

Gin

This template demonstrates building the Gin framework for Platform.sh using Go modules. It includes a minimalist application skeleton that demonstrates how to connect to a MariaDB server for data storage. It is intended for you to use as a starting point and modify for your own needs.

Gin is a lightweight web framework written in Go that emphasizes performance.

Features:

  • Go 1.14
  • MariaDB 10.4
  • Git module-based build

View the repository on GitHub.


Is this page helpful?