Self-hosted Prefect 3 on Railway — the Prefect server (API + UI) with a PostgreSQL database behind it, in one click.
Two templates, same stack, different halves of the job.
Prefect Server is the control plane on its own — the API, the UI and a database. Use it when you already have somewhere to run a worker, or you only want the dashboard.
Prefect + Worker adds the execution half. A Prefect server schedules work but
does not perform it: without a worker, a flow scheduled for 3am simply goes Late.
This template ships a worker that is already running, already authenticated and
already attached to a pool.
Both pin Prefect to the 3.8 line (prefecthq/prefect:3.8-python3.12, currently
3.8.2) and PostgreSQL to 18, so a deploy today and a deploy next month give you
the same Prefect minor while patch releases still arrive automatically.
Point your local Prefect at the deployed server:
prefect config set PREFECT_API_URL="https://<your-service>.up.railway.app/api"Open the same domain in a browser for the UI. To go back to a local server, or to Prefect's hosted control plane:
prefect config set PREFECT_API_URL="http://127.0.0.1:4200/api"
prefect cloud loginCredentials. The server is password-protected by default with a unique random password generated at deploy time. Find it in the Railway dashboard on the
prefect-serverservice under Variables →PREFECT_SERVER_API_AUTH_STRING, in the formadmin:PASSWORD. Clients and workers need the same value:prefect config set PREFECT_API_AUTH_STRING="admin:YOUR-PASSWORD". See Prefect's security settings.
A Prefect server schedules work but does not execute it — that's a worker's job. This repo contains one:
Deployed via the button? Eject the worker first. A deployed template attaches directly to this repository, which you cannot push to. In Railway: worker service → Settings → Source → Upstream Repo → Eject → pick your GitHub org → Eject service.
You then get your own copy, and everything after that is a file edit on github.com —
open flows/example_stars.py, click the pencil, replace it with your flow, commit.
Railway rebuilds and re-registers on boot. Railway also opens a pull request in your
copy whenever this template improves.
(Starting from scratch instead of the button? Just fork this repo.)
Then you only ever touch two things:
flows/ |
your flow code, plus prefect.yaml declaring which flows to register and on what schedule |
pyproject.toml |
your dependencies — uv add pandas, commit pyproject.toml and uv.lock |
Everything else is the worker itself: Dockerfile builds the image and
worker/entrypoint.sh waits for the server, runs prefect deploy --all against
flows/prefect.yaml, and starts polling. Push a change and Railway rebuilds — your
deployments re-register on boot.
uv sync # local dev environment
uv run python flows/example_stars.py # run a flow directly
uv add pandas # add a dependency, then commit pyproject.toml + uv.lockPrefect is open source by Prefect Technologies (Apache-2.0). This is a community template, not an official Prefect product.
