Skip to content

Deployment

Let's deploy the todo app to railway.app.

Prepare for Production

In this tutorial, we'll deploy both the React app and the API server as one server-side app, and redirect all non-API requests to return the React app.

We will deploy an ESM node server project

In addition, to follow a few basic production best practices, we'll use compression middleware to improve performance and helmet middleware for security

  1. Add the highlighted code lines to src/server/index.ts, and modify the app.listen function's port argument to prefer a port number provided by the production host's PORT environment variable.
ts
// src/server/index.ts

import express from "express"
import { api } from "./api.js"
import session from "cookie-session"
import { auth } from "./auth.js"

const app = express()
app.use(
  session({
    secret: process.env["SESSION_SECRET"] || "my secret"
  })
)
app.use(auth)
app.use(api)
const frontendFiles = process.cwd() + "/dist";
app.use(express.static(frontendFiles));
app.get("/*", (_, res) => {
  res.sendFile(frontendFiles + "/index.html");
});
app.listen(process.env["PORT"] || 3002, () => console.log("Server started"));
  1. Modify the highlighted code in the api server module to prefer a connectionString provided by the production host's DATABASE_URL environment variable.

    ts
    // src/server/api.ts
    
    //...
    const DATABASE_URL = process.env["DATABASE_URL"];
    
    export const api = remultExpress({
     dataProvider: DATABASE_URL
       ? createPostgresDataProvider({ connectionString: DATABASE_URL })
       : undefined,
       //...
     })

Note

In order to connect to a local PostgresDB, add DATABASE_URL to an .env file, or simply replace process.env["DATABASE_URL"] with your connectionString.

If no DATABASE_URL has found, it'll fallback to our local JSON files.

  1. Modify the project's build npm script to additionally transpile the API server's TypeScript code to JavaScript (using tsc).
json
// package.json

"build": "tsc && vite build && tsc -p tsconfig.server.json",
  1. Modify the project's start npm script to start the production Node.js server.
json
// package.json

"start": "node dist/server/"

The todo app is now ready for deployment to production.

Test Locally

To test the application locally run

sh
npm run build
npm run start

Build Errors

If you get an error error TS5096: Option 'allowImportingTsExtensions' can only be used when either 'noEmit' or 'emitDeclarationOnly' is set. do not set the emitDeclarationOnly flag!

You are getting the error because somewhere in your code you've imported from .ts instead of .js - fix it and build again

Now navigate to http://localhost:3002 and test the application locally

Deploy to Railway

In order to deploy the todo app to railway you'll need a railway account. You'll also need Railway CLI installed, and you'll need to login to railway from the cli, using railway login.

Click enter multiple times to answer all its questions with the default answer

  1. Create a Railway project.

    From the terminal in your project folder run:

    sh
    railway init
  2. Set a project name.

  3. Once that's done run the following command to open the project on railway.dev:

    sh
    railway open
  4. Once that's done run the following command to upload the project to railway:

    sh
    railway up
  5. Add Postgres Database:

    1. In the project on railway.dev, click + Create
    2. Select Database
    3. Select Add PostgresSQL
  6. Configure the environment variables

    1. Click on the project card (not the Postgres one)
    2. Switch to the variables tab
    3. Click on + New Variable, and in the VARIABLE_NAME click Add Reference and select DATABASE_URL
    4. Add another variable called SESSION_SECRET and set it to a random string, you can use an online UUID generator
    5. Switch to the settings tab
    6. Under Environment click on Generate Domain
    7. Click on the Deploy button on the top left.
  7. Once the deployment is complete -

  8. Click on the newly generated url to open the app in the browser and you'll see the app live in production. (it may take a few minutes to go live)

Note

If you run into trouble deploying the app to Railway, try using Railway's documentation.

That's it - our application is deployed to production, play with it and enjoy.

To see a larger more complex code base, visit our CRM example project

Love Remult?  Give our repo a star.⭐

MIT Licensed | Made by the Remult team with ❤️