NestJS × React × Railway:ブログUIを実装して本番環境へデプロイ

  • nestjs
    nestjs
  • react
    react
  • docker
    docker
  • prisma
    prisma
2024/10/25に公開

はじめに

ここまでの記事では、NestJSとPrismaを組み合わせて、APIの設計・運用基盤を整えてきました。
データモデル設計、リレーション定義、マイグレーション管理、テスト環境構築まで一通り完了し、バックエンドAPIの土台は実用レベルに達しています。

第5回となる今回は、いよいよフロントエンド(React)との接続に進みます。

APIを単独で作って終わるのではなく、ブラウザから実際にデータを操作できる状態に仕上げることが今回のゴールです。

フロントとバックエンドをつなぐ構成の全体像

この回では、次のような全体像を目指して進めていきます。

Image from Gyazo

  • Reactでフロントエンド画面を構築し、NestJS APIを呼び出します
  • NestJSはAPIだけでなく、Reactでビルドした静的ファイルも配信できるようにします
  • PostgreSQL(Dockerコンテナ)がバックエンドDBとして動作し、データの保存・取得を担います

最終的には、Dockerfileとdocker-composeを使ってこれらを一体化し、開発・テスト・本番環境それぞれでスムーズに動かせる構成を作ります。

前回までに準備できている状態の整理

前回(第4回)までで、以下の状態がすでに整っています。

  • NestJS+Prismaを使った記事投稿API(/postsエンドポイント)が動作している
  • PostgreSQL(Docker)と接続できるようになっている
  • 環境変数によるDB接続切り替え(開発・テスト環境)ができている
  • テスト環境用のリセットができる
  • PrismaClientとNestJSの連携設計が確立されている

つまり、API側はもうすぐにでもフロントエンドと連携できる状態です。今回はこのAPIを活用して、React側からデータ取得・表示・投稿まで進めていきます。


本記事の対象読者は、以下のような方を想定しています。

  • NestJSとPrismaでAPI基盤を作れたので、次はフロントエンドをつないで動かしたい方
  • Reactを使ったフロントエンド開発をこれから本格的に始めたい方
  • Dockerやデプロイ構成まで意識したフルスタック開発にチャレンジしたい方

今回も、一つ一つの作業を積み上げながら、着実に「開発・運用できるアプリケーション」を構築していきましょう。

この連載の全体像と今回の位置づけ

  1. NestJSで始めるWebアプリ開発 ─ ブログサイトを作りながら学ぶプロジェクト構成と設定管理
  2. NestJSで記事投稿APIを作ろう ─ Prisma導入とCRUD実装の基本
  3. アプリの信頼性を高める ─ ロギング・エラーハンドリング・テスト戦略
  4. PrismaとDB設計を深掘る ─ モデル・リレーション・運用設計
  5. ReactでUIを構築して本番へデプロイ ─ Dockerと環境構築 ← 今回の記事

今回のゴール

このブログ記事では、NestJS + React + Prisma + PostgreSQL を使って開発したブログアプリを、本番環境にデプロイするまでの一連の流れを記録しています。

具体的には、以下のような構成を目指します:

  • フロントエンド(React)とバックエンド(NestJS)を分離開発
  • PrismaでDBスキーマを管理し、PostgreSQLと接続
  • ViteやTailwind CSSなどの最新のフロントエンド開発環境を活用
  • Dockerを使って本番ビルド・統合
  • クラウドサービス「Railway」を使って、フルスタック構成を本番公開

Image from Gyazo

また、記事の後半では以下のポイントについても扱います:

  • Viteの環境変数の扱いと注意点(VITE_API_URL など)
  • Prismaのマイグレーションと本番DBへの適用
  • Railwayでの環境変数設定とDockerビルド戦略
  • Reactのビルド成果物を NestJS 経由で静的配信する構成

この記事を読み進めることで、個人開発やPoC、スタートアップの立ち上げにも使える「即戦力の本番構成」を、実際の手順に沿って追体験できます。

Reactアプリの作成と基本構成

ここでは、Reactアプリを新規作成し、開発しやすい構成を整えるところまで進めます。

Viteでプロジェクト作成(frontendディレクトリ)

Reactアプリを立ち上げる方法はいくつかありますが、今回はViteを使用して作成する方法を採用します。
(Create React Appでも進められますが、Viteの方がビルド速度が速く、開発体験が向上するためです)

まず、NestJSプロジェクト直下(/backendと並列の位置)に、frontendディレクトリを作成します。

cd <プロジェクトのルート>
npm create vite@latest frontend -- --template react-ts

コマンドの意味:

  • frontend という新しいディレクトリにReact+TypeScript構成のViteアプリを作成
  • --template react-ts により、最初からTypeScript対応

作成が完了したら、依存関係をインストールします。

cd frontend
npm install

これで、Reactアプリの初期セットアップが完了しました。

/frontend ディレクトリ構成

セットアップ直後のfrontendディレクトリは次のようになっています。

/frontend
  ├── public/
  ├── src/
      ├── App.tsx
      ├── main.tsx
  ├── index.html
  ├── package.json
  ├── tsconfig.json
  ├── vite.config.ts

この中のsrc/App.tsxを編集することで、Reactアプリケーションの画面を作っていく形になります。

Tailwind CSSの導入

今回は、シンプルなUIを素早く作るためにTailwind CSSを導入します。

インストール手順は次の通りです。

npm install tailwindcss @tailwindcss/vite

続いて、vite.config.tsを以下のように設定します。

vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), tailwindcss()],
})

最後に、src/index.cssを作成し、Tailwindの基本スタイルを読み込ませます。

@import "tailwindcss";

動作確認

セットアップが完了したら、実際に開発サーバーを立ち上げて、動作確認を行います。

cd frontend
npm run dev

ブラウザで http://localhost:5173 にアクセスし、初期画面(Viteのロゴと「Vite + React」表示)が出ればOKです。

さらに、Tailwindが正しく効いているかを確認するために、App.tsxを軽く編集してみます。

function App() {
  return (
    <div className="min-h-screen flex items-center justify-center bg-blue-100">
      <h1 className="text-4xl font-bold text-blue-800">
        Frontend is working!
      </h1>
    </div>
  );
}

export default App;

再読み込みして、背景が薄い青色 (bg-blue-100)、文字が濃い青色 (text-blue-800) に変わっていれば、Tailwindも正常に動いています。

Image from Gyazo

NestJSとの連携とAPI通信設定

APIエンドポイントの設定

まず、ReactアプリからNestJSサーバーへリクエストを送るために、環境変数でAPIエンドポイントを管理するようにします。frontend/.env ファイルを作成し、次のように記述します。

VITE_API_URL=http://localhost:3000

ReactからAPIエンドポイントを参照する際は、import.meta.env.VITE_API_URLを使います。
(※Viteの仕様上、環境変数にはVITE_プレフィックスが必須です)

記事投稿フォーム(PostForm.tsx)の作成

まず、投稿フォーム用のコンポーネントを作成します。
frontend/src/components/PostForm.tsx を作成し、次のように記述します。

frontend/src/components/PostForm.tsx
import { useState } from 'react';

type Props = {
  onPostCreated: () => void;
};

export function PostForm({ onPostCreated }: Props) {
  const [title, setTitle] = useState('');
  const [content, setContent] = useState('');

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();

    await fetch(`${import.meta.env.VITE_API_URL}/posts`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title, content }),
    });

    setTitle('');
    setContent('');
    onPostCreated();
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="bg-white p-8 rounded shadow-md space-y-4 w-full max-w-md"
    >
      <h1 className="text-2xl font-bold text-blue-700">新規記事投稿</h1>
      <div>
        <label className="block text-sm font-medium text-gray-700">タイトル</label>
        <input
          type="text"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          className="mt-1 block w-full border-gray-300 rounded-md shadow-sm"
          required
        />
      </div>
      <div>
        <label className="block text-sm font-medium text-gray-700">本文</label>
        <textarea
          value={content}
          onChange={(e) => setContent(e.target.value)}
          className="mt-1 block w-full border-gray-300 rounded-md shadow-sm"
          rows={4}
        />
      </div>
      <button
        type="submit"
        className="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 transition"
      >
        投稿する
      </button>
    </form>
  );
}
  • 投稿後にonPostCreated()コールバックを呼び、親コンポーネントで一覧を更新できるようにします。

記事一覧表示(PostList.tsx)の作成

続いて、記事一覧用のコンポーネントを作成します。
frontend/src/components/PostList.tsx を作成し、次のように記述します。

frontend/src/components/PostList.tsx
import { useEffect, useState } from 'react';

type Post = {
  id: number;
  title: string;
  content?: string;
};

export function PostList() {
  const [posts, setPosts] = useState<Post[]>([]);

  async function fetchPosts() {
    const response = await fetch(`${import.meta.env.VITE_API_URL}/posts`);
    const data = await response.json();
    setPosts(data);
  }

  useEffect(() => {
    fetchPosts();
  }, []);

  return (
    <div className="mt-12 w-full max-w-2xl">
      <h2 className="text-xl font-bold mb-4 text-blue-700">投稿一覧</h2>
      <ul className="space-y-4">
        {posts.map((post) => (
          <li key={post.id} className="p-4 bg-white rounded shadow">
            <h3 className="text-lg font-semibold">{post.title}</h3>
            {post.content && <p className="mt-2 text-gray-600">{post.content}</p>}
          </li>
        ))}
      </ul>
    </div>
  );
}
  • 初回レンダリング時に記事一覧を取得して表示します。

App.tsx(親コンポーネント)

最後に、src/App.tsxを次のように編集します。

src/App.tsx
import { PostForm } from './components/PostForm';
import { PostList } from './components/PostList';
import { useState } from 'react';

function App() {
  const [refreshKey, setRefreshKey] = useState(0);

  function handlePostCreated() {
    setRefreshKey((prev) => prev + 1);
  }

  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center p-8">
      <PostForm onPostCreated={handlePostCreated} />
      <PostList key={refreshKey} />
    </div>
  );
}

export default App;
  • 投稿後にrefreshKeyを更新して、PostListコンポーネントを再マウントすることで一覧を更新します。

動作確認

ここまで実装できたら、次の手順で動作を確認します。

  1. npm run dev でReactアプリを起動します
  2. http://localhost:5173 にアクセスします
  3. タイトルと本文を入力して「投稿する」ボタンをクリックします
  4. 成功すると一覧が自動更新され、新しい記事が表示されます

Image from Gyazo

必要に応じて npx prisma studio を起動し、DB上にも投稿内容が登録されていることを確認します

Image from Gyazo

※ CORSエラーが出る場合

ブラウザの仕様により、Reactアプリ(http://localhost:5173)からNestJSサーバー(http://localhost:3000)へリクエストを送ると、
セキュリティチェック(プリフライトリクエスト)が発生します。

NestJS側でこれに対応するため、src/main.tsに以下の設定を追加します。

src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { HttpExceptionFilter } from './common/filters/http/http.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());
+ app.enableCors();
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap().catch((err) => {
  console.error('Application failed to start', err);
});

これで、ブラウザ側からのリクエストが正しく許可され、登録動作がスムーズに行えるようになります。

ReactアプリをビルドしてNestJSで静的配信する

ReactアプリとNestJS APIが連携できるようになったので、次は、ビルドしたReactアプリをNestJS側で静的ファイルとして配信できる構成を整えます。

これにより、ブラウザからAPIもReact画面も一つのサーバーで扱えるようになり、開発・本番環境ともにシンプルで扱いやすい構成になります。

Reactアプリをビルドする

まず、frontendディレクトリでReactアプリをビルドします。

cd frontend
npm run build

正常終了すると、frontend/distディレクトリが生成されます。
この中に、HTMLやCSS、JavaScriptなど、ブラウザで動作する完成ファイル一式が出力されます。

NestJSで静的ファイルを配信する設定

NestJSでReactの静的ファイルを配信できるように、backend/src/main.tsに次の設定を追加します。

backend/src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { HttpExceptionFilter } from './common/filters/http/http.filter';
+ import { NestExpressApplication } from '@nestjs/platform-express';
+ import { join } from 'path';

async function bootstrap() {
+ const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());
  app.enableCors();
+ app.useStaticAssets(join(__dirname, '../../', 'frontend', 'dist'));
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap().catch((err) => {
  console.error('Application failed to start', err);
});

動作確認

NestJSを起動し、http://localhost:3000にアクセスすると、Reactで作成した画面が表示されるかと思います。

アクセスできましたら新規投稿もできるか確認します。

Image from Gyazo

フロントエンドとAPIのパス設計を整理する

ここまでで、Reactアプリをビルドし、NestJSで静的ファイルを配信できるようになりました。
しかしこのままだと、Reactアプリ側のパスと、NestJS側のAPIパスが衝突するリスクが残っています。

たとえば、ブラウザで /posts にアクセスするとき、
NestJSが「静的ファイル」だと誤認してしまったり、
逆にAPIリクエストがReact側に流れてしまったりする可能性があるからです。

そこで、フロントエンドの画面遷移と、バックエンドAPIのリクエストをきれいに分離するために、
APIリクエストには /api/ プレフィックスを付ける設計に切り替えます。

なぜ /api プレフィックスを付けるのか?

  • フロントエンドのルーティング(/posts/aboutなど)と
  • バックエンドAPIのルーティング(/api/posts/api/usersなど)

これを明確に分けることで、

  • ページリロード時に正しくindex.htmlを返す
  • APIリクエスト時は確実にNestJS側に到達させる

という、自然でトラブルのないリクエストハンドリングができるようになります。

変更作業

NestJS

Controller側で /api プレフィックスを付ける
たとえば、記事投稿API(PostsController)では次のように設定します。

backend/src/posts/posts.controller.ts
- @Controller('posts')
+ @Controller('api/posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Post()
  create(@Body() createPostDto: CreatePostDto) {
    return this.postsService.create(createPostDto);
  }

React

frontend/.env ファイルを編集し、次のように記述します。

VITE_API_URL=http://localhost:3000/api

動作確認

再度、NestJSを起動し新規投稿と投稿一覧が動くことを確認します。

Docker Composeを使った統合環境(frontend+backend+db)構築

ここまでで、フロントエンド・バックエンド・データベース(PostgreSQL)のそれぞれが個別に動作する状態になりました。次は、これらをDocker Composeを使って一括で起動できる開発環境を構築します。

具体的には、

  • docker-compose.dev.yml → 開発環境(ホットリロード対応)
  • docker-compose.prod.yml → 本番環境(ビルドして最適化)

をそれぞれ作り、シーンに応じた最適な起動方法を選べるようにします。
これにより、開発体験もデプロイ体験もスムーズかつ安全になります。

docker-compose.dev.ymlを作成する(開発用)

開発中は、ソースコードのリアルタイム反映を最優先します。そのため、ボリュームマウントでホストとコンテナを同期し、NestJS・React両方をホットリロードで動かします。

docker-compose.dev.yml

services:
  db:
    image: postgres:15
    container_name: nestjs-postgres-dev
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: nestjs_blog_dev
    volumes:
      - db-data-dev:/var/lib/postgresql/data

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    container_name: nestjs-backend-dev
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://postgres:postgres@db:5432/nestjs_blog_dev
    volumes:
      - ./backend:/app
    command: npm run start:dev
    depends_on:
      - db

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    container_name: react-frontend-dev
    ports:
      - "3001:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    command: npm run dev
    depends_on:
      - backend

volumes:
  db-data-dev:

Dockerfile.devを用意する

各サービスに開発専用のDockerfileを置きます。

backend/Dockerfile.dev
FROM node:20

WORKDIR /app

COPY package*.json ./
RUN npm install

CMD ["npm", "run", "start:dev"]
frontend/Dockerfile.dev
FROM node:20

WORKDIR /app

COPY package*.json ./
RUN npm install

CMD ["npm", "run", "dev"]

ポート番号を整理したいのでviteで起動する際のポート番号を変更します。

frontend/vite.config.ts
export default defineConfig({
  plugins: [react(), tailwindcss()],
+ server: {
+   host: "0.0.0.0",
+   port: 3000,
+ },
})

バックエンド、フロントエンド両方とも3000で起動し、バッティングしないようフロントエンドは3001でアクセスするように設定しました。

DBを新しく作成しましたのでマイグレーションを流します。

docker-compose exec backend npx prisma migrate deploy

動作確認

下記コマンドで起動します。

docker-compose -f docker-compose.dev.yml up --build

ビルドが毎回いるかというとそうではありません。
依存ライブラリを変えたときやDockerfile.devを変更した際はビルドが必要となりますが、そうでなければ下記コマンドで起動で問題ありません。

docker-compose -f docker-compose.dev.yml up

`http://localhost:3001/``にアクセスし投稿画面が表示されれば正常に起動できています。

ホットリロードが正常に動作するか確認するために「新規記事投稿」→「記事投稿」に修正してみます。

frontend/src/components/PostForm.tsx
  return (
    <form
      onSubmit={handleSubmit}
      className="bg-white p-8 rounded shadow-md space-y-4 w-full max-w-md"
    >
-     <h1 className="text-2xl font-bold text-blue-700">新規記事投稿</h1>
+     <h1 className="text-2xl font-bold text-blue-700">記事投稿</h1>
      <div>

修正内容がブラウザに反映されればOKです。

Image from Gyazo

Railwayを使って本番環境構築

Railwayとは?

Railway は、バックエンドやデータベースを “レールに乗せるように” 簡単にデプロイできる、開発者向けのクラウドプラットフォームです。

https://railway.com/

特にこんな特徴があります:

  • Docker対応:Dockerfileさえ用意すれば、任意のアプリケーションをそのままデプロイ可能
  • DB同時構築:PostgreSQL や Redis などのマネージドDBをワンクリックで作成・接続可能
  • 環境変数管理がラク:GUIで .env 相当の環境変数をセット、デプロイごとに適用される
  • 無料枠あり:軽い検証や個人開発に十分な無料プラン
  • Git連携:GitHubと接続すればプッシュごとに自動デプロイされる

こんな人・チームにおすすめ

  • 本番環境にとりあえず「今動くもの」を早く立てたい
  • フロントエンド + バックエンド + DB を一括で管理したい
  • Dockerベースでアプリを構築している
  • Heroku の代替を探している
  • 技術検証や個人開発で素早く PoC を回したい

Railway は、Dockerアプリ・NestJS・Prisma・PostgreSQL を組み合わせた構成でも、驚くほどスムーズにデプロイできるクラウドプラットフォームでした。複雑なCI/CDやインフラ構築に悩むより、「いま動くものを本番に出す」ための強力な選択肢として、とても信頼できます。

Railwayを使ってアプリを構築していく流れ

このプロジェクトでは、NestJSとReactで構成されたブログアプリを、クラウドプラットフォーム「Railway」を使って本番環境へデプロイします。
Railwayを使うことで、Dockerベースの構成でも柔軟に環境を構築でき、バックエンド・フロントエンド・データベースを一括して管理できます。

ここでは、実際にどのような手順で本番環境を立ち上げるか、流れをざっくり整理しておきます。

  1. Dockerfileの準備
    バックエンド(NestJS)とフロントエンド(React)をそれぞれDockerでビルドできる構成に
    本番用に Dockerfileを用意
    フロントはビルド後、NestJSが静的ファイルとして配信

  2. Railwayプロジェクトの作成
    Railwayにログインし、新しいプロジェクトを作成
    「Deploy from GitHub」のテンプレートを使って開始

  3. PostgreSQLインスタンスの追加
    「Deploy PostgreSQL」から PostgreSQL を選択して追加
    自動生成される DATABASE_PUBLIC_URLの環境変数を後で利用する

  4. Prismaの本番マイグレーション実行
    prisma/migrations をベースに、本番用のDBにマイグレーションを適用

  5. 環境変数(Variables)の設定
    .env.production に相当する値を Railway の GUI 上で登録
    フロントエンドとバックエンドのビルド時にこれらが参照されるようにする

  6. Railwayでデプロイをトリガー
    GitHub連携によってデプロイを開始
    Dockerfileの内容に従ってビルド → コンテナ起動 → アプリ公開

  7. 動作確認と修正
    https://xxxxx.up.railway.app でアプリが公開される
    APIのエンドポイントや環境変数にズレがないか確認
    必要に応じて再ビルド・再デプロイ

Dockerfileの準備

本番環境では、ソースコードをビルドした上で最適化された成果物のみをコンテナ化します。このため、ホットリロードは不要で、単純なビルド→起動の流れになります。
ローカルで本番環境を起動する機会はあまりないかと思いますが、こちらはこの後外部のサービスにデプロイする際に使用するものとなります。

# ビルドステージ
FROM node:20 AS builder

WORKDIR /app

# backendとfrontend両方コピー
COPY backend/package*.json backend/
COPY frontend/package*.json frontend/

# frontendビルド
WORKDIR /app/frontend
COPY frontend/ .
RUN npm install

ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL

RUN npm run build

# backendビルド
WORKDIR /app/backend
COPY backend/ .
RUN npm install
RUN npm run build

RUN npx prisma generate

# 実行ステージ
FROM node:20-slim

WORKDIR /app

# backendとfrontendまとめてコピー
COPY --from=builder /app .

ENV NODE_ENV=production
CMD ["node", "backend/dist/main.js"]

Dockerfileでエラーが発生しないかビルドとコンテナの起動で確認します。

docker build -t nestjs-blog-app .
docker run --rm -p 3000:3000 nestjs-blog-app

コンテナを起動すると下記のようにNestJSの起動中にデータベースへのアクセスでエラーが発生します。
本番用のデータベースにアクセスするのですがまだ作成しておりませんのでこのエラーが出てる状態で問題ありません。

Image from Gyazo

Railwayプロジェクトの作成

Railwayにログインし、新しいプロジェクトを作成

下記URLからアカウントを登録します。

https://railway.com/

アカウントを登録したら、「Deploy from GitHub repo」で今回作成したリポジトリを選択します。

Image from Gyazo

Railwayからアクセス可能なリポジトリについては下記の画面で設定可能です(全てのリポジトリをRailwayに公開する必要はありません)

Image from Gyazo

プロジェクトのトップにあるDockerfileを元に恐らくデプロイが開始しますが失敗すると思います。一旦そのままにしておきます。

PostgreSQLインスタンスの追加

次に本番環境用のデータベースを構築します。下記の画面から「Deploy PostgreSQL」を選択します。

Image from Gyazo

1分ほどで構築完了しデータベースにアクセスするための情報が表示されますのでこちらで「DATABASE_PUBLIC_URL」を控えておきます。

Image from Gyazo

Prismaの本番マイグレーション実行

ローカル環境で先ほど作成したPostgreSQLインスタンスに対してマイグレーションを実行します。

DATABASE_URL="..." npx prisma migrate deploy
  • DATABASE_URL: PostgreSQLインスタンスの追加で発行されたDATABASE_PUBLIC_URL

マイグレーションが正常終了するとRailwayからもDB情報を確認できるようになります。

Image from Gyazo

環境変数(Variables)の設定

再びDockerでデプロイするプロジェクトに戻り外部からアクセスするためのDomainを「Generate Domain」で生成します。(Railwayがhttps://xxxxx.up.railway.appという形式のDomainを生成してくれます)

Image from Gyazo

この値が、最終的にブラウザでアクセスするURLになります。

VariablesでDATABASE_URLとVITE_API_URLを設定します。

Image from Gyazo

  • DATABASE_URL: PostgreSQLインスタンスの追加で発行されたDATABASE_PUBLIC_URL
  • VITE_API_URL: 「Generate Domain」で発行された${URL}/api

Railwayでデプロイをトリガー

これで一通り設定が終わりましたのでデプロイを行い確認します。「Deploy from GitHub repo」の場合は対象のブランチにコミットすると自動でデプロイが行われますが、「Redeploy」で手動デプロイをすることも可能です。

Image from Gyazo

動作確認

「Generate Domain」で発行されたURLにアクセスすると今回作成されたブログアプリが表示され、投稿などができるかと思います。

Image from Gyazo

おわりに

ここまでで、NestJS + React + Prisma を組み合わせたブログアプリを、Dockerを使って本番ビルドし、クラウドプラットフォーム Railway にデプロイする一連の流れを整理しました。

単にローカルで動かすだけでなく、

  • 本番用のビルドと環境切り替え
  • PrismaマイグレーションとDB運用
  • フロントエンドとバックエンドの統合配信
  • Railwayでのコンテナ管理と環境変数設定

といった「実際に運用していくための準備」まで踏み込んだ内容になっています。

これらの作業は、一見すると地味で手間がかかるように思えるかもしれません。
しかし、開発初期から丁寧に整えておくことで、チーム開発や規模拡大、本番トラブル対応の場面で確実に大きなアドバンテージになります。

また、今回紹介した構成は、個人開発やスタートアップの立ち上げにもすぐに応用できるシンプルかつ強力なベースとなっています。

今後は、さらに運用を意識した改善(例:ステージング環境の構築や監視設定、認証まわり)にも挑戦していきます。
引き続き、より実践的なアプリケーション構成を構築いきましょう。

本記事が、開発・運用スキルの成長に少しでも役立てば嬉しいです。

Xでシェア
Facebookでシェア
LinkedInでシェア

記事に関するお問い合わせ📝

記事の内容に関するご質問、ご意見などは、下記よりお気軽にお問い合わせください。
ご質問フォームへ

技術支援などお仕事に関するお問い合わせ📄

技術支援やお仕事のご依頼に関するお問い合わせは、下記よりお気軽にお問い合わせください。
お問い合わせフォームへ

関連する技術ブログ

弊社の技術支援サービス

お問い合わせ

経営と現場をつなぐ“共創型”の技術支援。
成果に直結するチーム・技術・プロセスを共に整えます。

お問い合わせ