Deploying
steno build writes plain files into dist/ (or whatever you set output to): HTML, CSS,
JavaScript, images. There is no server, no database, and nothing that needs to keep running. That
means you can put it on almost any host built for static files. This page walks through the common
ones.
Every option below runs the same two commands, they just differ in where those commands run and where the result ends up:
deno install # only needed if the project has dependencies to fetch first
deno task build
If your project doesn't have a deno task build (for example, you didn't scaffold it with
deno create jsr:@steno/init), use
deno run --allow-read --allow-write --allow-net --allow-env jsr:@steno/steno build instead.
GitHub Actions
This workflow builds your site on every push to main and publishes it to GitHub Pages. Save it as
.github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- run: deno task build
- uses: actions/upload-pages-artifact@v3
with:
path: dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
Then turn on GitHub Pages for the repository (Settings, then Pages, then set Source to "GitHub
Actions"). If your project doesn't have a deno task build, replace that step's run: line with
the deno run ... command above.
You don't have to deploy to GitHub Pages specifically, this same
build-then-upload-pages-artifact shape works with almost any GitHub Actions deploy step; swap
the last job for whatever your host's official action is (see Vercel, Netlify, and Cloudflare Pages
below, most of them publish one).
Vercel, Netlify, and Cloudflare Pages
These three all work the same way: point them at your repository, tell them how to build your site and where the result lands, and they take care of the rest, including a new deployment on every push.
Whichever one you use, the settings are the same:
- Build command:
deno task build(or thedeno run ...command above if your project doesn't define that task) - Output directory:
dist - Framework preset: pick "Other" (or "None") since none of them know Steno specifically
The one thing to check is that Deno itself is available during the build. Some hosts have it preinstalled; if yours doesn't, add an install step before the build command:
curl -fsSL https://deno.land/install.sh | sh -s -- --yes
export PATH="$HOME/.deno/bin:$PATH"
deno task build
If you're on Cloudflare Pages (or any CDN in front of your site) and worried about stale cached CSS
or JavaScript after a redeploy, you don't need to do anything extra: Steno already gives theme CSS
and JS files a content hash in their filename by default, so a changed file gets a brand new URL
automatically. See hashAssets in
Configuration if you ever want to turn
that off.
Self-hosting (a server or a Docker container)
If you're running your own server, a VPS, or a platform like Dokploy or Coolify that expects a
long-running container, build the site the same way and then serve the dist/ folder with any
static file server. Don't use steno preview for this: it only listens on 127.0.0.1 (your own
machine), by design, so it is meant for a final local check before you ship, not for serving real
traffic.
A minimal Dockerfile that builds the site and serves it with Caddy:
FROM denoland/deno:2.9.4 AS build
WORKDIR /app
COPY . .
RUN deno task build
FROM caddy:2-alpine
COPY --from=build /app/dist /usr/share/caddy
Any other static file server works just as well, nginx, serve, Caddy, or your platform's built-in
one, as long as it binds to 0.0.0.0 (all interfaces) rather than 127.0.0.1, so traffic from
outside the container can actually reach it.
What to read next
- Configuration for
outputand other build-time settings. - Transactional builds for what happens if a build fails partway through, useful context if you're scripting deploys yourself.