Deploy for free
This puts Switchyard on the internet with free plans only, no credit card:
| Piece | Where | Free plan |
|---|---|---|
| Database | Neon Postgres | 0.5 GB storage, sleeps when idle |
| Server | Render web service, running the native image | 512 MB RAM, 750 hours a month (enough for one service around the clock) |
| Server image | GitHub Container Registry, built by GitHub Actions | Free for this repository |
| Dashboard | Cloudflare Pages | Unlimited static requests |
Allow about 30 minutes the first time. You need accounts on GitHub, Neon, Render and Cloudflare (all can sign up with GitHub).
1. Publish the server image
The Server image workflow (.github/workflows/image.yml) builds the native server and pushes it to ghcr.io/<your-github-user>/switchyard-server. It runs on every push to main; to run it now, open the repository's Actions tab, pick Server image, then Run workflow. It takes about 10 minutes.
Render needs to be able to pull the image. Either:
- Make the image public (simplest; the image holds no secrets): on GitHub, open your profile, Packages, switchyard-server, Package settings, Change visibility, Public. Or:
- Keep it private: create a GitHub personal access token (classic) with only
read:packages, and add it in Render under Account settings, Registry credentials (registryghcr.io, your GitHub username, the token).
2. Create the database on Neon
- In Neon, Create project. Pick the region closest to where you'll run the server (Render's free plan offers Oregon, Ohio, Virginia, Frankfurt and Singapore).
- On the project dashboard, Connect, and choose Java in the connection string menu. You get something like
jdbc:postgresql://ep-cool-name-123456.eu-central-1.aws.neon.tech/neondb?user=…&password=…&sslmode=require. - Split it into the three settings the server reads:
DATABASE_URL:jdbc:postgresql://ep-cool-name-123456.eu-central-1.aws.neon.tech/neondb?sslmode=requireDATABASE_USER: theuservalueDATABASE_PASSWORD: thepasswordvalue
The server creates its tables itself on first start.
3. Run the server on Render
- In Render, New, Blueprint, and connect this repository. Render reads
render.yamland proposes one web service calledswitchyard. - If your GitHub user isn't
nikolaviews, edit the image URL inrender.yamlfirst. - Fill in the values it asks for:
- The three
DATABASE_…values from Neon. SWITCHYARD_DASHBOARD_ORIGINS: leave empty for now; you'll know the dashboard's address after step 4.- Leave the
SWITCHYARD_GITHUB_…values empty unless you're setting up GitHub sign-in (step 5).
- The three
- Apply. When the deploy finishes, the service shows its address, like
https://switchyard-abcd.onrender.com. Openinghttps://switchyard-abcd.onrender.com/actuator/healthshould show{"status":"UP"}. - Render generated
SWITCHYARD_ADMIN_TOKEN. Find it under the service's Environment tab: that's your admin token for signing in.
Free plan sleep: Render's free services sleep after 15 minutes without requests and take a few seconds to wake up. Apps using a Switchyard client poll every 30 seconds, which keeps it awake; when nothing is connected, the first request after a quiet spell is slow. Clients keep using their last flags meanwhile.
4. Put the dashboard on Cloudflare Pages
- In Cloudflare, Workers & Pages, Create, Pages, Connect to Git, and pick this repository.
- Build settings:
- Framework preset: None
- Build command:
npm ci && npx ng build - Build output directory:
dist/dashboard/browser - Root directory:
dashboard - Environment variable:
NODE_VERSION=24
- Save and Deploy. You get an address like
https://switchyard.pages.dev. - Back in Render, set
SWITCHYARD_DASHBOARD_ORIGINSto that address (no trailing slash), and save. Render restarts the server. - Open the dashboard, enter the Render address as the server URL, and sign in with the admin token.
The dashboard is static files: it talks to the server straight from your browser, which is why the server must list its address.
5. GitHub sign-in (optional)
With this, your team signs in with their GitHub accounts instead of sharing the admin token, and History shows who made each change.
- On GitHub, open Settings, Developer settings, OAuth Apps, New OAuth App:
- Application name:
Switchyard - Homepage URL: your dashboard address, e.g.
https://switchyard.pages.dev - Authorization callback URL: your server address plus
/auth/github/callback, e.g.https://switchyard-abcd.onrender.com/auth/github/callback
- Application name:
- Register application, then Generate a new client secret. Copy the secret now; GitHub shows it only once.
- In Render, set:
SWITCHYARD_GITHUB_CLIENT_ID: the app's Client IDSWITCHYARD_GITHUB_CLIENT_SECRET: the secretSWITCHYARD_GITHUB_ADMINS: who's an admin, e.g.alice(you, at least)SWITCHYARD_GITHUB_ALLOWED_USERS: everyone else who may sign in, e.g.bob,carol. They start as editors (SWITCHYARD_GITHUB_DEFAULT_ROLEchanges that); admins change roles on the Members pageSWITCHYARD_GITHUB_CALLBACK_URL: the same callback URL as in step 1
- Save. The dashboard's sign-in page now shows Continue with GitHub.
Removing someone from SWITCHYARD_GITHUB_ALLOWED_USERS signs them out on their next request. Sessions last 12 hours (SWITCHYARD_SESSION_TTL).
To try GitHub sign-in locally, register a second OAuth app with the callback http://localhost:8080/auth/github/callback and run the server with the same four settings.
6. Connect your apps
Create a project in the dashboard. It shows each environment's SDK key once: put the production key in your app's secrets, and point a client library at the Render address. See the Java client and the JavaScript client.
Running the image anywhere else
The image is an ordinary container. It listens on PORT (default 8080) and reads everything else from the environment variables above:
docker run -p 8080:8080 \
-e DATABASE_URL=jdbc:postgresql://db.example.com/switchyard \
-e DATABASE_USER=switchyard -e DATABASE_PASSWORD=… \
-e SWITCHYARD_ADMIN_TOKEN=… \
-e SWITCHYARD_DASHBOARD_ORIGINS=https://flags-dashboard.example.com \
ghcr.io/nikolaviews/switchyard-server:latestTo build it yourself, from the repository root: docker build -f server/Dockerfile -t switchyard-server . (needs about 6 GB of memory for Docker).
The public website (optional)
The site folder builds the project's website: a landing page, plus the user guide, this guide and the client docs as web pages. It is plain static files, so it goes on Cloudflare Pages like the dashboard, as a second Pages project:
- Workers & Pages, Create, Pages, Connect to Git, and pick this repository again.
- Build settings:
- Framework preset: None
- Build command:
npm ci && npm run build - Build output directory:
dist - Root directory:
site - Environment variable:
NODE_VERSION=24
- Save and Deploy. The site rebuilds on every push to
main, so editing a doc in the repository updates its page.
The website is separate from the dashboard and never talks to the server. To look at it locally: cd site && npm ci && npm run build && npm run preview, then open http://localhost:4300.