Skip to content
Latchkey

CI/CD for a Bun + Elysia App with GitHub Actions

Install with Bun, test Elysia against Postgres, type-check, and build a Docker image on every push.

This recipe runs a Bun + Elysia API. CI installs with bun, runs bun test against a Postgres service container, type-checks, then builds a Docker image on the official Bun base image for deployment.

What the pipeline does

  • set up Bun
  • install with bun install --frozen-lockfile
  • run bun test against Postgres
  • type-check with tsc
  • build and push a Docker image

The workflow

oven-sh/setup-bun installs Bun. A Postgres service backs the data layer; the image is built on oven/bun for a fast cold start.

.github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]
  pull_request:
jobs:
  build:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: app
        ports: ["5432:5432"]
        options: >-
          --health-cmd "pg_isready" --health-interval 10s
          --health-timeout 5s --health-retries 5
    env:
      DATABASE_URL: postgres://postgres:postgres@localhost:5432/app
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest
      - run: bun install --frozen-lockfile
      - run: bun run tsc --noEmit
      - run: bun test
      - if: github.ref == 'refs/heads/main'
        run: |
          echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
          docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
          docker push ghcr.io/${{ github.repository }}:${{ github.sha }}

Caching and speed

setup-bun caches the Bun install, and you can cache ~/.bun/install/cache keyed on bun.lockb. Bun installs and tests are fast; cheaper managed runners such as Latchkey (around 69% cheaper than GitHub-hosted) keep the build-and-push loop quick and auto-retry a flaky image pull.

Deploying

Build the image FROM oven/bun:1 with a copied bun.lockb and source, then run bun run start. Push to GHCR with the built-in GITHUB_TOKEN (packages: write) and roll it out once tests pass on main.

Key takeaways

  • Install with --frozen-lockfile so CI matches the committed lockfile.
  • Back Elysia data tests with a Postgres service container.
  • Build the image on oven/bun for a fast runtime cold start.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →