目次
Vite + React + PostgreSQL環境の作り方
フロントエンド開発だけでなく、APIやDBまで含めて動かしたいケースは多くなっています。
しかし、フロントエンドエンジニアで「Vite + React」の環境は構築できても、「Vite + React + PostgreSQL」環境は構築できない人が多いのが実情です。
この記事では、Vite + React + PostgreSQLを組み合わせた開発環境をなるべく簡単に構築する方法を解説します。
※ Reactから直接PostgreSQLに接続することはできないため、必ずAPIサーバー(Express)を間に挟む構成にしています。
Dockerをインストールして起動する
PostgreSQLをローカルに簡単に立てるためにDockerを使用します。
Dockerの公式サイトからDocker Desktopをインストールして起動するだけでOKです。
起動するとメニューバーにDockerのアイコンが表示されます。

Vite + ReactとDockerの環境を準備
Vite + React + PostgreSQL環境は以下のディレクトリ構成で作成します。
my-app/
├─ package.json
├─ docker-compose.yml
├─ pnpm-workspace.yaml
├─ db/init.sql ← 起動時に実行するSQLファイル(読み込むデータ)
├─ client/ ← Vite + React
└─ server/ ← Express
まず最初にmy-appディレクトリを作成して移動します。
mkdir my-app
cd my-app次にVite + Reactをインストールします。
pnpm create vite@latest client --template react-ts「Install with pnpm and start now?」が表示されるので、Yesを選択してインストールします。
Install with pnpm and start now?
● Yes / ○ Noインストールが完了すると起動してlocalhostのURLからアクセスできますが、まだブラウザで確認しないので「control + C」で起動を停止します。
「cd client」で移動してReact Compilerをインストールします。
現在のReactを使用する開発環境ではメモ化を自動化するReact Compilerが必要不可欠なので設定しておきます。
cd client
pnpm add -D babel-plugin-react-compiler @rolldown/plugin-babelReact Compilerの設定を有効にするために、vite.config.tsを以下のように変更します。
serverのproxyはフロントエンド(Vite)からバックエンド(APIサーバー)へのリクエストを転送するためのものなので、こちらも必須です。
import { defineConfig } from 'vite'
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
import babel from '@rolldown/plugin-babel'
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
babel({ presets: [reactCompilerPreset()] }),
],
server: {
proxy: {
'/api': 'http://localhost:3001',
},
},
})client内のApp.tsxは fetch('/api/users') でユーザーの一覧を取得するページにします。
import { useEffect, useState } from 'react'
type User = {
id: number
name: string
}
export default function App() {
const [users, setUsers] = useState<User[]>([])
useEffect(() => {
const fetchUsers = async () => {
const res = await fetch('/api/users')
const data: User[] = await res.json()
setUsers(data)
}
fetchUsers()
}, [])
return (
<main>
<h1>Users</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</main>
)
}ルートディレクトリにpnpm-workspace.yamlを作成します。
packages:
- client
- server
ignoredBuiltDependencies:
- esbuildルートディレクトリにpackage.jsonも作成します。(clientのpackage.jsonではない)
「pnpm dev」を実行するとDockerとViteの両方が起動するようにしています。
{
"name": "my-app",
"private": true,
"scripts": {
"dev": "docker compose up -d && pnpm -r --parallel --stream dev",
"db:down": "docker compose down"
}
}PostgreSQLをDockerで起動するために、ルートディレクトリにdocker-compose.ymlを作成します。
services:
db:
image: postgres:17
container_name: my_postgres
restart: unless-stopped
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: apppass
POSTGRES_DB: appdb
ports:
- '5433:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
volumes:
postgres_data:ルードディレクトリにdbディレクトリを作成して、その中にinit.sqlを作成するコマンドを実行します。
mkdir db
cat <<'EOF' >> db/init.sql
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO users (name) VALUES
('Tanaka'),
('Suzuki')
ON CONFLICT DO NOTHING;
EOF「pnpm dev」コマンドの実行時に自動でinit.sqlを読み込むようにしています。
サーバーの環境を作成する
まず、以下のコマンドでルートディレクトリにserverディレクトリを作成して、Expressサーバーを作成します。
mkdir server
cd server
pnpm init
pnpm add express pg cors dotenv
pnpm add -D typescript tsx @types/node @types/express @types/pg @types/corsserverディレクトリ内のpackage.jsonのscriptsに「"dev": "tsx watch src/index.ts"」を追加します。
これがないとプロジェクトフォルダで「pnpm dev」を実行した際に、serverディレクト内のAPIサーバー(Express)が起動しないので必ず記載してください。
{
// 略
"scripts": {
"dev": "tsx watch src/index.ts"
}
// 略
}serverディレクトリ内にtsconfig.jsonを作成します。
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true
},
"include": ["src"]
}serverディレクトリ内に.envを作成します。
.envにはデータベースに接続するURLが書かれています。
DATABASE_URL=postgresql://appuser:apppass@localhost:5433/appdbserverディレクトリ内にsrcディレクトリを作成して、その中にdb.tsとindex.tsを作成して、GET APIが動作するようにします。
import pg from 'pg'
import dotenv from 'dotenv'
dotenv.config()
const { Pool } = pg
export const pool = new Pool({
connectionString: process.env.DATABASE_URL,
})import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
import { pool } from './db'
dotenv.config()
const app = express()
const port = Number(process.env.PORT || 3001)
app.use(cors())
app.use(express.json())
app.get('/api/users', async (_req, res) => {
const result = await pool.query('SELECT id, name FROM users ORDER BY id')
res.json(result.rows)
})
app.listen(port, () => {
console.log(`server running on http://localhost:${port}`)
})以上の手順が完了したら、ルートディレクトリで「pnpm dev」を実行すると、Dockerおよびフロントとバックエンドのサーバーが起動します。
pnpm dev「pnpm dev」実行時に以下のメッセージが表示される場合は、Docker Desktopが起動していないので、Docker.appを選択して起動してください。
$ pnpm dev
unable to get image 'postgres:17': Cannot connect to the Docker daemon at unix:///Users/iwb/.docker/run/docker.sock. Is the docker daemon running?
ELIFECYCLE Command failed with exit code 1.以上の手順が完了していれば、http://localhost:5173/ にアクセスした際に画面上にTanakaとSuzukiが表示されます。

もしも、以上の手順で画面に表示されない場合は、どこかの手順に漏れがあります。
実際に起動可能なGitHubリポジトリが以下のURLにありますので、うまくいかない場合は参考にしてください。
https://github.com/iwbjp/my-app-vite-react-postgresql
PostgreSQLに接続してデータを追加する方法
この記事では起動時にdb/init.sqlからテーブルを作成してデータを追加しています。
手動でやりたい場合は、以下のコマンドをターミナルで実行してPostgreSQLに接続します。
docker exec -it my_postgres psql -U appuser -d appdbPostgreSQLに接続すると、ターミナルの先頭が「$」から「appdb=#」に変わります。
$ docker exec -it my_postgres psql -U appuser -d appdb
psql (17.9 (Debian 17.9-1.pgdg13+1))
Type "help" for help.
appdb=#この状態でSQL文を実行してテーブルを追加します。
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO users (name) VALUES
('Tanaka'),
('Suzuki')
ON CONFLICT DO NOTHING;appdb=# は exit; で終了できます。
appdb=# exit;まとめ
Vite + React + PostgreSQLの開発環境は、一見すると難しそうに見えますが、Dockerを活用することで比較的シンプルに構築できます。
この構成にしておくことで、実務に近い形で開発を進めることができ、将来的にAWSやVPSなどへデプロイする際にもスムーズに移行できます。
フロントエンドエンジニアでもバックエンドやDBを含めた環境を扱えるようになると、開発の幅が大きく広がるので、ぜひこの構成をベースに応用してみてください。



