# 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](https://app.salus.cloud/register).
-   **GitHub or GitLab connected** to your Salus organization. See [Git Management](https://salus.cloud/docs/getting-started/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:

```text
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](https://salus.cloud/docs/deployments/environment-configurations/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](https://salus.cloud/docs/getting-started/quickstart/).

Or ask your coding agent, once it’s [connected to Salus](https://salus.cloud/docs/guides/deploy-with-an-ai-agent/):

```text
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](https://salus.cloud/docs/deployments/databases/provisioning/) in the same region as the environment and [link it to the project](https://salus.cloud/docs/deployments/databases/connect/). 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`:

```js
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.
