# What it took to deploy the SaaS Dashboard kit from a clean clone

> Three deploy attempts show what worked, why the earlier attempts did not leave a usable database, and which parts of the SaaS Dashboard setup remain untested.
> By Dave · 2026-10-10
> Source: https://otf-kit.dev/blog/saas-dashboard-kit-deploy-run-record

A deployment guide is most useful when it separates what its author actually ran from what a buyer still has to verify. We tested the delivered SaaS Dashboard kit from a clean clone against a throwaway Railway project. One later run deployed successfully; health checks followed, and the database migration, seed, and application checks happened afterward. The custom-domain path was not tested.

The useful detail is that it took more than one attempt. An early run used a commit without the migration files. A later migration attempt used the app’s private database hostname from a local machine and failed to resolve it. The successful run used a public TCP proxy for the local database commands. Those are different failure modes, and they show why “the app deployed” and “the database is ready” need separate checks.

## What the successful run covered

On 10 October 2026 at 01:23 UTC, setup and `railway up --detach --ci` succeeded for delivered mirror `c83f587`. At 01:24 UTC, `GET /` and `GET /api/health` returned 200, before the migration. The run then created the TCP proxy and ran `bun run db:migrate` and `bun run db:seed` locally with `DATABASE_URL` set only for those commands. After the seed, `POST /api/demo-login`, `GET /api/issues`, sign-up, and sign-in returned 200. The record does not give those later checks their own minute. Demo login returned the demo user’s session. The seeded demo dataset contained 4 users, 5 projects, 50 issues, 105 issue-labels, 30 comments, and 10 notifications. These are counts from this test project, not expected counts for your own data. No elapsed deployment time was measured.

## The setup steps we ran

For the successful test, the recorded setup ran these Railway CLI operations in sequence: `railway init`, `railway add --service`, `railway service link`, `railway add --database postgres`, `railway domain`, and `railway variable set` for the database reference, auth secret, and public URL. The recorded deploy command was `railway up --detach --ci`, which completed successfully. The public [SaaS Dashboard deployment guide](https://otf-kit.dev/docs/templates/saas-dashboard) currently shows login and link steps, but those two commands were not run in this recorded setup; the transcript used the project/service setup above. It does not publish secret values, and credentials should stay out of source control and transcripts. This test used a throwaway project; it does not establish that another project’s settings are correct.

## Why the earlier attempts did not leave a usable database.

The earliest recorded attempt deployed commit `ec96d1d`. That commit did not contain the migration files. The deploy succeeded and demo-login returned HTTP 500. That result is a reminder to check which delivered commit you are deploying and whether its migration files are present before treating a successful build as a usable app.

A later attempt deployed successfully, but invoked `railway run bun run db:migrate` with the app’s private database address. It failed with `ENOTFOUND postgres.railway.internal`: the private hostname could not be resolved from the local machine. This was a connectivity problem, distinct from the missing migration files in the earlier commit.

![A local migration cannot resolve the private database hostname; the TCP proxy provides a route to the database.](https://cdn.otf-kit.dev/blog/saas-dashboard-kit-deploy-run-record/inbody-01-migration-network-20261010a.png)

## How the successful migration was run

The successful run created a TCP proxy for the Postgres service, then ran `bun run db:migrate` and `bun run db:seed` locally with `DATABASE_URL` set for those commands. The kit's `docs/DEPLOYMENT.md` documents the proxy command. The public page [does not print it](https://otf-kit.dev/docs/templates/saas-dashboard). The command is:

```bash
railway tcp-proxy create --port 5432 --service Postgres
```

The connection string uses the proxy’s host and port rather than the private `postgres.railway.internal` hostname. `docs/DEPLOYMENT.md` explains how to read the Postgres variables and build that URL. The public page does not. Treat the values as credentials: do not paste them into chat, tickets, or commits. The successful migration and seed completed in the throwaway project.

At delivered commit `c83f587`, `server/db/seed.ts` uses inserts with `onConflictDoNothing`; it does not delete or truncate existing data. That is what ran in the throwaway project. `GETTING_STARTED.md` at that commit had a stale note claiming reseeding truncates app tables; current delivered `GETTING_STARTED.md` no longer says that. The kit's current `docs/DEPLOYMENT.md` matches the seed code: it says existing rows are skipped and advises against seeding a database that holds, or will hold, real users. The public page does not say that. A demo credential is documented in the README, so review demo access before sharing the deployed app. This run did not test removing the TCP proxy afterward; `docs/DEPLOYMENT.md` lists `railway tcp-proxy list` and `railway tcp-proxy delete`, and those cleanup commands were not run.

## What the checks establish

The HTTP 200 checks establish that those endpoints and auth requests responded successfully in that test environment. The demo-login session belonged to the demo user. They do not prove that every sign-in provider, email configuration, permissions rule, or production security setting is ready for your application.

![The deployed demo passes health and sign-in checks, while custom-domain verification remains separate.](https://cdn.otf-kit.dev/blog/saas-dashboard-kit-deploy-run-record/inbody-02-deployment-verification-20261010a.png)

Configure and test the auth paths you intend to offer. The kit guide lists the required environment variables and optional provider credentials; use your own settings and callback URLs. Test your application’s important flows after deployment rather than relying only on the health endpoint.

## What remains untested

The test generated and used a Railway service domain, but did not run the custom-domain setup steps. It also did not run the Fitness kit’s backend. If your launch needs a custom hostname, plan and verify that work separately, including DNS, TLS, and any authentication callback changes. A healthy service URL does not prove that a custom domain is configured.

The run covered the SaaS Dashboard deployment and initial database setup from a clean clone. It did not test upgrading an existing production database, OAuth setup, removing the TCP proxy, or the Fitness backend. Treat those as separate tasks in your launch checklist.

## Is a self-deployed kit the right starting point?

If you want a delivered codebase and are comfortable operating your own hosting project, the run offers a concrete baseline: one recorded clean-clone deployment succeeded, and the database setup succeeded once run through the TCP proxy. If you want a managed deployment where another party owns the hosting account, database, domain, and ongoing operations, a self-deployed kit is not that service.

The kit supplies code and a deployment guide; you select the hosting project, configure its environment, and verify the result. Our broader [deployment comparison](https://otf-kit.dev/blog/ai-agents-vs-manual-deployment) discusses which deployment tasks a builder still owns across different approaches. Use it as context, not as proof of this kit’s behavior.

## Buyer verification checklist

Before treating your own deployment as ready:

- Confirm the deployed commit includes the migration files.
- Check that the CLI is linked to the intended project and service.
- Set the required environment variables in the target environment.
- Make sure the migration can reach Postgres through the TCP proxy.
- Confirm migration completes before testing database-backed routes.
- Test the health endpoint and the sign-in paths you plan to offer.
- Configure and verify any custom domain separately.
- Review the seed warning and demo credentials before exposing the demo.

The honest claim is a documented setup path and one successful recorded run after two earlier failures—not a guarantee for every project, a one-command launch, or a measured time-to-deploy.

## Sources

- [SaaS Dashboard Kit deployment guide](https://otf-kit.dev/docs/templates/saas-dashboard) (read 10 October 2026).