Deploying with Railway in Strapi version >4.6.2 (4.10.5)

System Information
  • Strapi Version: 4.10.5
  • Operating System: MacOS
  • Database: Postgres

It seems like all of the guides that explained how to deploy Strapi with Railway are out of date and are no longer relevant to Strapi versions 4.6.2 and over. I’m using the latest version (4.10.5) and struggling link my Strapi instance on Railway to a Postgres database.

In the newer versions of Strapi apparently you just need to edit the config/database.js file as it has separate objects for sqlite (local development) and Postgres (production). I’ve changed the keys so they match the environment variables on Railway, so it’s like this:

postgres: { connection: { connectionString: env("DATABASE_URL"), host: env("PGHOST", "localhost"), port: env.int("PGPORT", 5432), database: env("PGDATABASE", "strapi"), user: env("PGUSER", "strapi"), password: env("PGPASSWORD", "strapi") } }

and with this I expected it to just sort of work but apparently I’m missing a step because the Postgres table on Railway is empty, it has no tables etc.

Could anyone advise how best to deploy? Thanks!

I won’t be able to elaborate much at the moment, but I just moved my project running on the latest strapi release to Railway without a problem. After I changed the Strapi env variables to match the Railway Postgres env vars, strapi started creating the tables on Railway automatically. here are my 2 files in the .config/env/production folder:
database.js

const path = require('path');

module.exports = ({ env }) => {
  const client = env('DATABASE_CLIENT', 'sqlite');

  const connections = {
    mysql: {
      connection: {
        connectionString: env('DATABASE_URL'),
        host: env('DATABASE_HOST', 'localhost'),
        port: env.int('DATABASE_PORT', 3306),
        database: env('DATABASE_NAME', 'strapi'),
        user: env('DATABASE_USERNAME', 'strapi'),
        password: env('DATABASE_PASSWORD', 'strapi'),
        ssl: env.bool('DATABASE_SSL', false) && {
          key: env('DATABASE_SSL_KEY', undefined),
          cert: env('DATABASE_SSL_CERT', undefined),
          ca: env('DATABASE_SSL_CA', undefined),
          capath: env('DATABASE_SSL_CAPATH', undefined),
          cipher: env('DATABASE_SSL_CIPHER', undefined),
          rejectUnauthorized: env.bool(
            'DATABASE_SSL_REJECT_UNAUTHORIZED',
            true
          ),
        },
      },
      pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
    },
    mysql2: {
      connection: {
        host: env('DATABASE_HOST', 'localhost'),
        port: env.int('DATABASE_PORT', 3306),
        database: env('DATABASE_NAME', 'strapi'),
        user: env('DATABASE_USERNAME', 'strapi'),
        password: env('DATABASE_PASSWORD', 'strapi'),
        ssl: env.bool('DATABASE_SSL', false) && {
          key: env('DATABASE_SSL_KEY', undefined),
          cert: env('DATABASE_SSL_CERT', undefined),
          ca: env('DATABASE_SSL_CA', undefined),
          capath: env('DATABASE_SSL_CAPATH', undefined),
          cipher: env('DATABASE_SSL_CIPHER', undefined),
          rejectUnauthorized: env.bool(
            'DATABASE_SSL_REJECT_UNAUTHORIZED',
            true
          ),
        },
      },
      pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
    },
    postgres: {
      connection: {
        connectionString: env('DATABASE_URL'),
        host: env('DATABASE_HOST', 'localhost'),
        port: env.int('DATABASE_PORT', 5432),
        database: env('DATABASE_NAME', 'strapi'),
        user: env('DATABASE_USERNAME', 'strapi'),
        password: env('DATABASE_PASSWORD', 'strapi'),
        ssl: env.bool('DATABASE_SSL', false) && {
          key: env('DATABASE_SSL_KEY', undefined),
          cert: env('DATABASE_SSL_CERT', undefined),
          ca: env('DATABASE_SSL_CA', undefined),
          capath: env('DATABASE_SSL_CAPATH', undefined),
          cipher: env('DATABASE_SSL_CIPHER', undefined),
          rejectUnauthorized: env.bool(
            'DATABASE_SSL_REJECT_UNAUTHORIZED',
            true
          ),
        },
        schema: env('DATABASE_SCHEMA', 'public'),
      },
      pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
    },
    sqlite: {
      connection: {
        filename: path.join(
          __dirname,
          '..',
          env('DATABASE_FILENAME', 'data.db')
        ),
      },
      useNullAsDefault: true,
    },
  };

  return {
    connection: {
      client,
      ...connections[client],
      acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
    },
  };
};

server.js

module.exports = ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  app: {
    keys: env.array('APP_KEYS'),
  },
  webhooks: {
    populateRelations: env.bool('WEBHOOKS_POPULATE_RELATIONS', false),
  },
});

.env file should look like this:

APP_KEYS=xxxxxxxxxx
API_TOKEN_SALT=xxxxxxxx
ADMIN_JWT_SECRET=xxxxx
TRANSFER_TOKEN_SALT=xxxxxxx
JWT_SECRET=BuI4Yxxxxxxxx
//i pasted the environment variables from railway postgres like so:
DATABASE_CLIENT=postgres
DATABASE_HOST=containers-us-west-xxxx.railway.app
DATABASE_PORT=6124
DATABASE_NAME=railway
DATABASE_USERNAME=postgres
DATABASE_PASSWORD=SDxxxxxxxxxxxxxx
DATABASE_SSL=false

Hi @solidstatesociety, thanks for your help!

I’ve created 2 files:
/config/env/production/database.js
/config/env/production/server.js

And pasted your code, I’ve also updated my .env file to match the values from the environment variables automatically set up in Railway. However, when I deploy it still doesn’t seem to do anything with the Postgres database on Railway. I also noticed that on Railway the environment variable keys are different to Strapi, eg. on Railway it’s PGUSER not DATABASE_USERNAME. However I tried both the keys you used and the keys on Railway and neither worked anyway.

Any ideas? Thanks again

You’re welcome! You should keep the environment variable names the same on strapi, unless you want to change where those variables are declared in the two files you mentioned. At the end of the day, Strapi is looking at the value of those variables anyways. So copy the variable values from Railway and paste them into your environment variables on your .env file in Strapi.

I would test running strapi locally first to see if you can connect to the remote database. Once that’s working, you can then create a Strapi app on Railway.

You should be running Strapi with

NODE_ENV=production yarn start

on your local machine to test the connection with the remote DB.
I saw somewhere that you should have a separate file for the production environment called: .env.production
You should copy the existing stuff on your .env file there.
If you can provide some logs that would help too. I don’t want to suggest something wrong without seeing what’s really happening.

Is there any tutorial on how to deploy to Railway? I’m planning to move my portfolio’s backend soon!

1 Like

Just follow this steps in the template Deploy Strapi on Railway | Railway :wink:

That template does not work now. This is the build logs:

[Region: us-west1]

==============

Using Nixpacks

==============

context: 6975bab838bae93e592b14b85b21c505

╔══════════════ Nixpacks v1.19.0 ═════════════╗

β•‘ setup β”‚ nodejs_21, yarn-1_x β•‘

║─────────────────────────────────────────────║

β•‘ install β”‚ yarn install --frozen-lockfile β•‘

║─────────────────────────────────────────────║

β•‘ build β”‚ yarn run build β•‘

║─────────────────────────────────────────────║

β•‘ start β”‚ yarn run start β•‘

β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

#0 building with β€œdefault” instance using docker driver

#1 [internal] load .dockerignore

#1 transferring context: 2B done

#1 DONE 0.0s

#2 [internal] load build definition from Dockerfile

#2 transferring dockerfile: 2.81kB done

#2 DONE 0.0s

#3 [internal] load metadata for Package nixpacks Β· GitHub

#3 DONE 0.3s

#4 [stage-0 1/10] FROM ghcr.io/railwayapp/nixpacks:ubuntu-1699920194@sha256:c861ec45a7401768f59183a4a51056daf7dd26ab9a5215836c81b09725b9cbb6

#4 DONE 0.0s

#5 [internal] load build context

#5 transferring context: 481.96kB done

#5 DONE 0.0s

#6 [stage-0 2/10] WORKDIR /app/

#6 CACHED

#7 [stage-0 3/10] COPY .nixpacks/nixpkgs-bf744fe90419885eefced41b3e5ae442d732712d.nix .nixpacks/nixpkgs-bf744fe90419885eefced41b3e5ae442d732712d.nix

#7 CACHED

#8 [stage-0 4/10] RUN nix-env -if .nixpacks/nixpkgs-bf744fe90419885eefced41b3e5ae442d732712d.nix && nix-collect-garbage -d

#8 CACHED

#9 [stage-0 5/10] COPY . /app/.

#9 DONE 0.0s

#10 [stage-0 6/10] RUN --mount=type=cache,id=s/52d35a24-7f70-4aba-a6e8-f6e3ddcc1bc9-/usr/local/share/cache/yarn/v6,target=/usr/local/share/.cache/yarn/v6 yarn install --frozen-lockfile

For me it worked in abt 10 minutes all in. My steps:

  1. from the railway dashboard choose New Project >> Deploy a template

  2. Type β€œStrapi”, it is the template from Milo

  3. under both sevices (Postgres and Strapi) choose β€œConfigure” and choose β€œSave config”. I did not change anything, eventhough you could set a repo name for your github here.

  4. click β€œDeploy” and wait (it took some minutes to build here)

After that note the project name, that railway assigns to your project, you need it in step 6.

Now go into your github repos and choose the newly created repo and clone it on your local machine and cd into it.

(for the following you need to have railway cli installed β€œnpm i -g @railway/cli”)

  1. log into railway by β€œrailway login”

  2. enter β€œrailway link”, choose the project name from the railway dashboard and choose β€œStrapi” (not Postgresql)

  3. run β€œnpm install” (for some reason for me yarn did not work)

  4. now run β€œrailway run npm run develop” (yes, two times β€œrun”)

Now you should be able to open strapi locally under 127.0.0.1:1337/admin and create an admin.

Changes you do locally will be reflected in your Postgresql on railway.

So e.g. create the admin locally.

Now if you go to your app from your railway dashboard you will see the app in production and under
/admin you can login with the admin you created locally.

Is it free? at least cheap?