How to deploy a Vue.js Single Page Application (SPA) with a Golang API on


Deploy a Vue.js Single Page Application (SPA) with a Golang API backend on



Two strategies are possible when building an SPA with

  • creating two separate projects for Vue.js frontend and Golang API backend
  • hosting both apps within a single multi-app Platform project (requires at least a Medium plan)

This How-to shows the second option.

Steps (Multi-app SPA)

1. Project structure

Ultimately, the project structure will look like the following (one common .platform directory, and one file per app):


2. Set Up Golang App

1. Create the Go Project

Create and enter a project directory vuespa. Create a hello_world_backend directory, and then create the following hello_world.go file within that directory:

// vuespa/hello_world_backend/hello_world.go

package main

import (

	psh ""

// Greetings is a basic Greetings to user
type Greetings struct {
	Message string `json:"message"`

// sayHello returns greetings to user in JSON format
func sayHello(w http.ResponseWriter, r *http.Request) {

	greetings := Greetings{Message: "Hello World!"}

	returnedJSON, err := json.Marshal(greetings)
	if err != nil {
		http.Error(w, "Internal server error", http.StatusInternalServerError)

	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, "%s", returnedJSON)

func main() {

	// Load environment variables in order to retrieve correct port
	p, err := psh.NewPlatformInfo()
	if err != nil {
		panic("Not in a Environment.")

	// Initialize HTTP server
	mux := http.NewServeMux()

	// Set up the /say-hello API endpoint
	mux.HandleFunc("/say-hello", sayHello)

	// Enable CORS and Whitelist the frontend domain in order to comply with
	// CORS Allowed Origins policy
	handler := cors.New(cors.Options{
		AllowedOrigins: []string{"https://your-platformsh-frontend-url"},

	// Launch HTTP server with custom port retrieved in env var
	http.ListenAndServe(":"+p.Port, handler)

The above exposes a say-hello REST endpoint returning a greetings message to user.

CORS need to be properly handled as both frontend and backend apps are not hosted at the same URLs. Ideally the frontend URL whitelisted in CORS (https://your-platformsh-frontend-url) should be retrieved through an environment variable.

For more information about CORS please visit:

The frontend url will not be made available until the project is pushed to for the first time, so it may be necessary to push the code once to establish those routes, and then commit the url once they are defined.

In general, they will take the forms https://https://master-7rqtwti-<project ID>.<project region> for the frontend url and https://https://backend.master-7rqtwti-<project ID>.<project region> for the backend url.

2. Set up the configuration

Create a within the directory:

# vuespa/hello_world_backend/

name: go-backend

# Use the Golang 1.12 image
type: golang:1.12

# A Medium plan is necessary for multi-app
size: M

  # Get dependencies and build Go app
  build: |
    go get ./...
    go build -o bin/app

    socket_family: tcp
    protocol: http

  # Launch the Go server
    start: ./bin/app

      allow: false
      passthru: true

disk: 1024

3. Set Up Vue.js App

1. Initialize the Vue.js project

Create the Vue.js base project with the Vue CLI, selecting the default install option when prompted:

$ vue create hello_world_frontend

cd into hello_world_frontend and install the axios dependency:

$ npm install axios

2. Update The Vue.js Project

Remove everything inside the src directory except the main.js file and add the following App.vue file:

<!-- vuespa/hello_world_frontend/src/App.vue -->

  <div id="app">
    <p v-if="msg">
      Retrieved the following greetings message from API Go backend:
      <b>{{ msg }}</b>
    <p v-if="msgError">
      Error while getting message from Go API backend:
      <b>{{ msgError }}</b>

import axios from 'axios'
export default {
  name: 'app',
  data() {
    return {
      msg: '',
      msgError: '',
  mounted: function () {
      .then(response => {
        if (response.status === 200) {
          if ( {
            this.msg =
          } else {
            this.msgError = 'Got no data from API'
        } else {
          this.msgError = 'Got an ok but unhandled HTTP response from API'
      .catch(e => {
        if (e.response) {
          if (e.response.status === 500) {
            this.msgError = 'Got an internal server error from API'
          } else {
            this.msgError = 'Got an unhandled error HTTP response from API'
        } else if (e.request) {
          this.msgError = 'Got no response when contacting API server'
        } else {
          this.msgError = 'Got an unhandled error when contacting API server'


3. Set up the configuration

Now create a with the following:

# vuespa/hello_world_frontend/

name: vuejs-frontend

type: nodejs:10

# A Medium plan is necessary for multi-app
size: M

  build: |
    npm install
    npm run build

# There is no need for a writable file mount, so set it to the smallest possible size.
disk: 256

    # Run a no-op process that uses no CPU resources, since this is a static site.
    start: sleep infinity
      root: "dist"
        - "index.html"
      # Set a 5 minute cache lifetime on all static files.
      expires: 300s
      # Disable all scripts, since we don't have any anyway.
      scripts: false
      # By default do not allow any files to be served.
      allow: false
      # Whitelist common image file formats, plus HTML files, robots.txt
      # All other requests will be rejected.
          allow: true
          allow: true

4. Set Up Routes and Services

In the root directory create a .platform directory. Create a routes.yaml file.

# vuespa/.platform/routes.yaml

  type: upstream
  upstream: "go-backend:http"
  type: upstream
  upstream: "vuejs-frontend:http"

Create an empty services.yaml file.

# vuespa/.platform/services.yaml

5. Deploy

Set the repository’s remote to an empty project using its project ID, which can be found within the Web UI or by listing the accounts active projects with the CLI, platform project:list.

$ platform project:set-remote <project ID>

Commit changes and deploy.

$ git init
$ git add .
$ git commit -m "Init commit"
$ git push platform master

6. Verify

Visit the frontend URL to see the following message:

Retrieved the following greetings message from API Go backend: Hello World!


Setting Up a Vue.js SPA + Golang API within a muti-app project on is pretty simple. It requires no local compilation and the project is instantly testable via an HTTPS URL.

An improvement would be to dynamically retrieve the backend URL in the frontend app (for API results fetching), and conversely to retrieve the frontend URL in the backend app (for CORS whitelisting).