Back to Blog
Tutorial11 min read2026-06-27

How to Deploy a Buffalo Go Web App

Buffalo is a Rails-like full-stack Go framework with asset pipelines and migrations built in. Learn how to deploy a Buffalo app to production with Pop migrations and a managed database.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Buffalo is the Go ecosystem's answer to Rails — a batteries-included full-stack framework with a frontend asset pipeline, ORM (Pop), migrations (Soda/Fizz), generators, and a dev server. That convenience comes with a more involved build than a bare Go router, because you have both Go code and a Webpack-based frontend to compile. This guide covers deploying a Buffalo app to production.

What Buffalo bundles

A Buffalo app includes:

  • Actions (handlers) and a router.
  • Pop — the ORM, configured via database.yml.
  • Fizz/Soda migrations for schema management.
  • An asset pipeline (Webpack by default) for JS/CSS.
  • Plush templates for server-rendered HTML.

The key deployment insight: Buffalo can build a single binary that embeds compiled templates and assets via buffalo build. That binary is what you ship.

Building for production

Locally, buffalo build compiles assets and embeds them into one binary:

buffalo build --static -o bin/app

The --static flag produces a statically-linked binary. But in a container you want this to happen reproducibly during the image build, so let's express it as a Dockerfile.

The multi-stage Dockerfile

Buffalo's official base images simplify this, since they include Node and the Buffalo CLI:

# ---- Build ----
FROM gobuffalo/buffalo:v0.18.14 AS build
WORKDIR /src/app

COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN buffalo build --static -o /bin/app

# ---- Runtime ----
FROM alpine
RUN apk add --no-cache bash ca-certificates
WORKDIR /bin/
COPY --from=build /bin/app .
COPY --from=build /src/app/migrations ./migrations
ENV GO_ENV=production
EXPOSE 3000
CMD ["/bin/app"]

We copy the migrations/ directory into the runtime image so we can run them as a release step. The GO_ENV=production flag switches Buffalo into production behavior.

Database configuration with Pop

Pop reads database.yml, but in production you should drive it from the DATABASE_URL env var. Buffalo/Pop natively honor DATABASE_URL, overriding the production block in database.yml:

# database.yml
production:
  dialect: postgres
  url: {{ envOr "DATABASE_URL" "" }}

With a managed PostgreSQL instance linked, DATABASE_URL is injected and Pop connects directly. No credentials in your repo.

Running migrations

Buffalo uses Soda (the migration tool inside Pop) to apply Fizz migrations. Run them as a release step before the new version takes traffic:

/bin/app migrate

Buffalo's built binary includes the migrate subcommand, so you don't need a separate tool. On PandaStack, wire /bin/app migrate as a once-per-release job. Avoid running migrations on every pod boot — with multiple replicas you'd race concurrent migrations.

The PORT and binding

Buffalo reads the PORT and ADDR env vars. In a container, set ADDR=0.0.0.0 so it binds to all interfaces and PORT to whatever the platform injects:

ADDR=0.0.0.0
PORT=3000  # or the injected value

If you forget ADDR=0.0.0.0, Buffalo may bind to 127.0.0.1 and the platform's health checks won't reach it.

Session secret

Buffalo signs session cookies with SESSION_SECRET. Set a stable, random value as a secret env var:

SESSION_SECRET=$(openssl rand -hex 32)

Generate once and keep it stable; rotating it logs everyone out on each deploy.

Environment variables

VariablePurpose
GO_ENVproduction
DATABASE_URLinjected by managed DB link
ADDR0.0.0.0
PORTinjected listen port
SESSION_SECRETcookie signing key

Asset serving

Because buffalo build embeds compiled assets into the binary (when built with packing), the single binary serves your CSS/JS. For high-traffic sites you might front static assets with a CDN, but the embedded approach keeps deployment to a single artifact — exactly Buffalo's design goal.

Health checks

Add a simple action returning 200 and route it at /health, then point the platform's readiness probe at it. Keep it free of DB access for the liveness probe.

Deploying

Push the repo, connect it, link a managed PostgreSQL database, set the env vars above, and add the /bin/app migrate release step. The platform builds the multi-stage Dockerfile (asset pipeline included) and rolls it out. Live build logs surface Webpack or Go compile errors immediately.

git push origin main

When Buffalo fits

Buffalo suits teams who want Rails-like productivity in Go: server-rendered apps with forms, sessions, and a built-in asset pipeline. For pure JSON APIs, a lighter router like Chi or Echo is leaner. Buffalo's value is the integrated full-stack experience.

Conclusion

Buffalo deploys as a single self-contained binary once you handle the dual Go+frontend build, drive Pop from the injected DATABASE_URL, run migrate as a release step, set ADDR=0.0.0.0 and a stable SESSION_SECRET. The integrated tooling pays off for full-stack apps.

Try a Buffalo app with a managed PostgreSQL on PandaStack's free tier — connect your repo at [dashboard.pandastack.io](https://dashboard.pandastack.io) and the database auto-wires via DATABASE_URL.

References

  • [Buffalo Documentation](https://gobuffalo.io/documentation/)
  • [Buffalo: Deploying to Production](https://gobuffalo.io/documentation/deploy/)
  • [Pop / Soda (ORM and Migrations)](https://gobuffalo.io/documentation/database/pop/)
  • [Fizz Migration DSL](https://gobuffalo.io/documentation/database/fizz/)
  • [Buffalo Docker Images](https://hub.docker.com/r/gobuffalo/buffalo)

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also