Move a Replit app to Salus

An app built on Replit runs on Salus as it is: Salus builds it from your repository with buildpacks, without a Dockerfile, and runs it under your organization’s rules. Two things Replit did for you need setting by hand: the port and the secrets.

This guide was tested on Salus with an Express app and a FastAPI app laid out the way Replit exports them.

Before you begin

  • A Salus account. Start free.
  • GitHub or GitLab connected to your Salus organization. See Git Management.
  • The Replit project in a Git repository. From Replit’s Git pane, connect the project to a new GitHub repository and push.

Check how the app starts, and on which port

Replit starts your app with the run command in .replit, and sends traffic to the port under [[ports]], usually through a PORT variable it sets. Salus doesn’t set PORT, so an app written as process.env.PORT || 3000 listens on 3000 on Salus. Note that port; you’ll give it to Salus in step 3.

  • Node.js: make sure package.json has a start script (for example "start": "node index.js"). Salus runs it.
  • Python: add a Procfile at the root of the repository with the command that starts your server, on a fixed port. For FastAPI:
web: uvicorn main:app --host 0.0.0.0 --port 8080

Keep requirements.txt up to date; Salus installs from it. Replit’s .replit and replit.nix files are ignored.

Move the secrets

Everything in Replit’s Secrets pane becomes an environment variable on Salus. Add each one to the project, marked as a secret, and as a runtime variable unless the build needs it. See Environment Variables.

Create the project and deploy

In the console, create a project from the repository as a server-side application and set the release configuration’s port to the one from step 1. See the Quickstart.

Or ask your coding agent, once it’s connected to Salus:

Deploy this repository to Salus in the Production environment.
It listens on port 3000. Watch the pipeline and give me the URL.

The pipeline builds, tests, scans and deploys the app, and the deployment gets a URL when it’s exposed to the public.

Move the database

If the app used Replit’s PostgreSQL, create a database on Salus in the same region as the environment and link it to the project. Linking injects the connection details as variables named after the database, such as SALUS_DATABASE_ORDERS_DB_CONNECTION_STRING. Point the app at that variable where it used to read DATABASE_URL:

const connectionString =
  process.env.SALUS_DATABASE_ORDERS_DB_CONNECTION_STRING ?? process.env.DATABASE_URL;

The data doesn’t move with the app. Export it from Replit with pg_dump and load it into the new database.

Replit’s key-value Replit DB has no equivalent on Salus; store that data in a table in the PostgreSQL database instead.

Troubleshooting

  • The pipeline passed but the URL returns 502. The app listens on a different port from the one in the release configuration. The pipeline doesn’t check the port, so a wrong one still deploys “successfully”. Set the port to match, and redeploy.
  • A Python build fails to start: no start command. Add the Procfile from step 1, with a web: line.
  • The app can’t read a secret. Check it was added as a runtime variable. Build-time variables aren’t available to the running app.
  • Linked database variables are missing. They’re injected on the next deploy after the link shows Linked, and only at runtime, not during the build.