Skip to content


Let's deploy the todo app to

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. In addition, to follow a few basic production best practices, we'll use compression middleware to improve performance and helmet middleware for security

  1. Install compression and helmet.
npm i compression helmet
npm i @types/compression --save-dev
  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.
// src/server/index.ts

import express from "express"
import { api } from "./api"
import session from "cookie-session"
import { auth } from "./auth"
import helmet from "helmet"
import compression from "compression"
import path from "path"

const app = express()
    secret: process.env["SESSION_SECRET"] || "my secret"
app.use(express.static(path.join(__dirname, "../")))
app.get("/*", (_, res) => {
  res.sendFile(path.join(__dirname, "../", "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.

    // src/server/api.ts
    export const api = remultExpress({
      dataProvider: createPostgresDataProvider({
        connectionString: process.env["DATABASE_URL"] || "your connection string"
  2. In the root folder, create a TypeScript configuration file tsconfig.server.json for the build of the server project using TypeScript.

// tsconfig.server.json

  "compilerOptions": {
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "rootDir": "src"
  "include": ["src/server/**/*", "src/shared/**/*"]
  1. Modify the project's build npm script to additionally transpile the API server's TypeScript code to JavaScript (using tsc).
// 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.
// package.json

"start": "node dist/server/"

The todo app is now ready for deployment to production.

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:

    railway init
  2. Select Empty Project

  3. Set a project name.

  4. Once it's done add a database by running the following command:

    railway add
  5. Select postgressql as the database.

  6. Once that's done run the following command to upload the project to railway:

    railway up
  7. got to the railway project's site and click on the project

  8. Switch to the variables tab

  9. Click on + New Variable, and in the VARIABLE_NAME click Add Reference and select DATABASE_URL

  10. Add another variable called SESSION_SECRET and set it to a random string, you can use an online UUID generator

  11. Switch to the settings tab

  12. Under Environment click on Generate Domain

  13. 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)


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 ❤️