web / paas

From 2009-2023, I deployed my database-backed web apps to Heroku. When I wanted to move to a new provider, I created croaky/webstack to prototype different PaaS stacks.

Based on the location of users of my app, I set up API checks via Checkly from Northern California and London. Each stack served a healthcheck-style HTTP API endpoint that executed a SELECT 1 to a SQL database and responded with JSON {"status":"ok"}. Each stack used a lightweight router, a SQL database driver (no ORM), and a database connection pool. Example:

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/jackc/pgx/v4/pgxpool"
)

func main() {
	// env
	port, ok := os.LookupEnv("PORT")
	if !ok {
		port = "8080"
	}
	dbUrl, ok := os.LookupEnv("DATABASE_URL")
	if !ok {
		dbUrl = "postgres:///webstack_dev"
	}

	// db
	db, err := pgxpool.Connect(context.Background(), dbUrl)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// routes
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		var col int
		db.QueryRow(r.Context(), "SELECT 1").Scan(&col)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintf(w, "{\"status\":\"ok\"}")
	})

	// listen
	log.Println("Listening at http://localhost:" + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

Heroku

My baseline Heroku workflow was:

While performance and reliability were good on Heroku, my confidence was shaken when its GitHub integration broke in April 2022 and it took over a month to be resolved.

Heroku also lacked some long overdue features such as HTTP/2 support and it was not possible to restrict access to its Postgres database from public internet without a major increase in cost.

Render

I ended up choosing Render and Crunchy Bridge Postgres. This combo felt like the smallest step from Heroku. I felt both companies were mature orgs and my software would be reliable.

Some things I liked about Render:

Crunchy Bridge was a good fit for me because I am "all-in" on Postgres, using it as a transactional database and for my job queues.

I deploy to Render with a small Go CLI: cmd / deploy.

Other considerations

I sometimes web and background services on virtual machines.

← All articles