1. はじめに
Web開発の世界では「リアルタイム性」がますます重要になっています。SNSやチャットアプリ、掲示板といったサービスでは、ユーザーが投稿した内容が即座に反映されることが当たり前になりました。
しかし、従来のサーバー構築やWebSocket実装には手間がかかり、学習コストも高めです。
そこで注目されているのが、Next.js と Supabase の組み合わせです。
- Next.js:Reactベースのフレームワークで、サーバーサイドレンダリングやAPI Routesをサポート。モダンWeb開発の定番。
- Supabase:Firebaseの代替として注目されるBaaS(Backend as a Service)。認証、データベース(PostgreSQL)、リアルタイム通信まで揃う。
この2つを組み合わせれば、難しい設定を最小限に抑えて「リアルタイム掲示板」を短時間で構築できます。
本記事では、ゼロから環境を構築し、リアルタイムに投稿が更新される掲示板アプリを作る流れを、実際のコードを交えて解説していきます。
2. なぜNext.jsとSupabaseを組み合わせるのか?
掲示板やチャットアプリを開発する際、従来は以下のような選択肢がありました。
- Node.js + Express + Socket.io
- Firebase(Firestore + Authentication)
- GraphQL + Apollo Subscriptions
どれも強力ですが、初学者にとっては構築ハードルが高いのも事実です。
一方で、Next.jsとSupabaseを組み合わせると以下のメリットがあります。
- データベースが自動でリアルタイム化
SupabaseはPostgreSQLベースながら、行の追加・更新を自動的にPush配信してくれます。 - Next.jsのAPI Routesで柔軟に拡張可能
投稿APIや認証処理など、バックエンドをシンプルに組み込める。 - 学習コストが低い
ReactやSQLの基本を知っていれば、複雑なWebSocketの知識がなくても構築可能。
結果として、シンプルに始められて、拡張性もあるという点で非常に実用的です。
3. 今回作るアプリの概要
本記事で作るのは「リアルタイム掲示板アプリ」です。
機能は以下の通り。
- ユーザーがテキストを投稿できる
- 投稿内容がリアルタイムで他のユーザーの画面に反映される
- 投稿はSupabaseのデータベースに保存される
シンプルですが、チャットアプリやSNS開発の基礎になる構成です。
まずは動くものを作り、その後に認証やUI改善を追加することで、実践的なプロダクトに成長させられます。
4. 環境構築
まずは開発環境を整えます。
必要なもの
- Node.js(v18以上推奨)
- npm または yarn
- Supabaseアカウント(無料で作成可能)
プロジェクトの作成
npx create-next-app realtime-board
cd realtime-board
続いて、Supabaseのクライアントライブラリを導入します。
npm install @supabase/supabase-js
Supabaseプロジェクト作成
- Supabase公式サイト にアクセスし、無料アカウントを作成。
- 新しいプロジェクトを作成し、データベースパスワードを設定。
- 「Table editor」から掲示板用のテーブルを作成します。
例:messages テーブル
カラム名型設定idbigint主キー、自動採番contenttext投稿内容created_attimestamptzデフォルト: now()
このテーブルに投稿を保存し、リアルタイムで反映させます。
5. Supabaseクライアントのセットアップ
Next.js内でSupabaseを扱えるよう、クライアントを設定します。
lib/supabaseClient.js を作成。
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
.env.local にSupabaseのプロジェクト情報を記載します。
NEXT_PUBLIC_SUPABASE_URL=あなたのSupabaseプロジェクトURL
NEXT_PUBLIC_SUPABASE_ANON_KEY=公開anonキー
これでNext.jsからSupabaseを操作できるようになりました。
Next.jsで掲示板の基本UIを構築する
前章ではSupabaseのセットアップとリアルタイム機能の基盤を準備しました。ここからはいよいよNext.js側でフロントエンドを構築していきます。本章のゴールは「最低限の掲示板UI」を作り、投稿内容を一覧表示できるようにすることです。
掲示板の基本構成
掲示板といっても、初期段階では以下の要素が揃っていれば十分です。
- 投稿一覧(ユーザーが書き込んだ内容が時系列で並ぶ)
- 投稿フォーム(テキスト入力と送信ボタン)
まずはシンプルにこれらを実装し、リアルタイム連携は次章で組み込みます。
Next.jsでページとコンポーネントを準備する
Next.jsではappディレクトリ(またはpagesディレクトリ)を使ってページを定義します。今回は「掲示板」をトップページに置くイメージで進めます。
// app/page.tsx
"use client";
import { useState, useEffect } from "react";
import { supabase } from "../lib/supabaseClient";
type Post = {
id: number;
content: string;
created_at: string;
};
export default function Home() {
const [posts, setPosts] = useState<Post[]>([]);
const [newPost, setNewPost] = useState("");
// 投稿一覧を取得
useEffect(() => {
const fetchPosts = async () => {
const { data, error } = await supabase
.from("posts")
.select("*")
.order("created_at", { ascending: false });
if (!error && data) {
setPosts(data);
}
};
fetchPosts();
}, []);
// 投稿処理
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!newPost.trim()) return;
const { error } = await supabase.from("posts").insert([{ content: newPost }]);
if (!error) {
setNewPost("");
// 投稿後に再取得(リアルタイム対応は次章で)
const { data } = await supabase
.from("posts")
.select("*")
.order("created_at", { ascending: false });
if (data) setPosts(data);
}
};
return (
<main className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-4">リアルタイム掲示板</h1>
{/* 投稿フォーム */}
<form onSubmit={handleSubmit} className="mb-6">
<textarea
className="w-full p-2 border rounded-md"
value={newPost}
onChange={(e) => setNewPost(e.target.value)}
placeholder="ここに投稿内容を入力..."
/>
<button
type="submit"
className="mt-2 px-4 py-2 bg-blue-500 text-white rounded-md"
>
投稿する
</button>
</form>
{/* 投稿一覧 */}
<div className="space-y-4">
{posts.map((post) => (
<div key={post.id} className="p-4 border rounded-md">
<p>{post.content}</p>
<span className="text-sm text-gray-500">
{new Date(post.created_at).toLocaleString()}
</span>
</div>
))}
</div>
</main>
);
}
このコードでは以下の処理を行っています。
- useEffectでSupabaseから投稿一覧を取得
- handleSubmitで新しい投稿を追加し、再取得
- 投稿フォームと一覧をシンプルなUIで表示
シンプルながら動く掲示板が完成
ここまでで、Next.jsとSupabaseを組み合わせた「シンプルな掲示板」が動く状態になります。投稿フォームから内容を送信すると、Supabaseに保存され、一覧に表示される仕組みです。
まだ「リアルタイム性」は導入していませんが、まずはこのシンプルな形で動作を確認することが重要です。
次章では、この掲示板に「リアルタイム更新機能」を追加し、複数人が同時にアクセスしても自動で投稿が反映されるようにしていきます。
Supabaseでリアルタイム通信を実装する
さて、基本的な掲示板の投稿機能とデータ取得ができるようになったところで、このプロジェクトの肝となる「リアルタイム通信機能」を実装していきます。リアルタイム性が加わることで、ユーザーがページをリロードしなくても新しい投稿が即時に表示され、掲示板としての利便性が大きく向上します。
Supabaseのリアルタイム機能とは?
SupabaseにはRealtime機能があり、Postgresの変更をWebSocketを通じて通知してくれる仕組みがあります。これにより、あるユーザーがデータベースに新規投稿を追加すると、他のユーザーの画面にも即座に反映されるのです。
特にチャットや掲示板のようなアプリケーションでは必須ともいえる機能で、Next.jsと組み合わせることでスムーズに実装が可能になります。
リアルタイム購読の基本コード
まず、supabase-jsのリアルタイムAPIを使って新しい投稿を購読します。
import { useEffect } from 'react'
import { supabase } from '../lib/supabaseClient'
export default function RealtimePosts({ onNewPost }) {
useEffect(() => {
const channel = supabase
.channel('custom-all-channel')
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'posts' },
(payload) => {
console.log('新しい投稿が追加されました:', payload.new)
onNewPost(payload.new)
}
)
.subscribe()
return () => {
supabase.removeChannel(channel)
}
}, [onNewPost])
return null
}
上記のコードでは、postsテーブルに新しいデータが追加された際に、onNewPost関数を呼び出しています。これを親コンポーネントで受け取り、状態を更新すれば、リアルタイム表示が可能になります。
投稿一覧にリアルタイム機能を組み込む
次に、掲示板の一覧表示コンポーネントにこの購読処理を組み込みます。
import { useState, useEffect } from 'react'
import { supabase } from '../lib/supabaseClient'
import RealtimePosts from './RealtimePosts'
export default function PostList() {
const [posts, setPosts] = useState([])
useEffect(() => {
fetchPosts()
}, [])
async function fetchPosts() {
let { data: posts, error } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
if (error) console.error(error)
else setPosts(posts)
}
function handleNewPost(newPost) {
setPosts((current) => [newPost, ...current])
}
return (
<div>
<RealtimePosts onNewPost={handleNewPost} />
<ul>
{posts.map((post) => (
<li key={post.id}>
<strong>{post.username}</strong>: {post.content}
</li>
))}
</ul>
</div>
)
}
このようにすることで、他のユーザーが投稿した内容が即時に自分の画面にも反映されます。つまり「リアルタイム掲示板」が完成するわけです。
リアルタイム化の効果と工夫
リアルタイム掲示板を実装すると、次のような体験が可能になります。
- 投稿が即座に他のユーザーへ反映されるため、会話のようなやり取りが可能
- ユーザーのエンゲージメントが高まり、掲示板としての価値が向上
- リロード不要で軽快に動作するため、モダンなUI/UXを実現
さらに実用化を考えると、リアルタイムで削除や更新も検知できるようにすると、より本格的なサービスとして利用できます。
4. Supabaseのリアルタイム機能をNext.jsに組み込む
掲示板の「命」ともいえるのがリアルタイム更新機能です。通常のデータベースは新しい投稿が追加されても自動で画面に反映されるわけではありません。しかし、SupabaseのリアルタイムAPIを利用すると、WebSocketを通じて変更が即座にクライアントへ配信されます。これにより、ユーザーがF5を押さなくても新しい書き込みが瞬時に表示される仕組みを作れます。
リアルタイム購読の実装イメージ
Next.js側でSupabaseクライアントを使い、以下のような流れで購読を行います。
- postsテーブルに対して購読を開始
- 新しい投稿がINSERTされるたびにコールバックを実行
- フロントエンドのstateを更新し、即時に反映
コードの概要は以下のようになります。
useEffect(() => {
const channel = supabase
.channel('public:posts')
.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'posts' }, (payload) => {
setPosts((prev) => [payload.new, ...prev]);
})
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, []);
このように数行のコードで、掲示板にリアルタイム性を持たせることができます。特にチャットや掲示板、通知機能を持つサービスでは不可欠な要素であり、Supabaseはその点で非常に強力です。
5. 投稿フォームとUI/UXの工夫
掲示板の投稿フォームはユーザーが毎回利用する重要なポイントです。単純にテキストを入力するだけでなく、UXを高める工夫が求められます。
例えば:
- 投稿後にフォームを自動クリア
- Enterキーで投稿可能にする
- 投稿エラー時に即時フィードバックを返す
Next.jsではReact Hook Formやバリデーションライブラリを組み合わせることで、効率的に実装できます。ユーザー体験を向上させることは、リアルタイム更新と同じくらい大事な部分です。
6. 認証を加えて「匿名投稿」と「ログイン投稿」を切り替える
掲示板では「匿名性」と「ユーザー認証」のバランスが課題になります。Supabaseは標準で**Email/Password認証やOAuth(Google, GitHubなど)**をサポートしており、簡単に導入可能です。
実際の掲示板では以下のような設計が考えられます。
- 認証なし → 匿名ユーザーとして投稿
- 認証あり → 名前やアイコン付きで投稿
このように柔軟に認証を組み込むことで、シンプルさを維持しつつ拡張性のある掲示板を作ることができます。
7. 掲示板をもっと便利にする「拡張機能」
シンプルな掲示板が完成したら、次は使いたくなる仕掛けを加えていきましょう。ここでは代表的な拡張機能を3つ紹介します。
(1) いいね機能(リアクション機能)
ユーザーが投稿に対して「いいね」や「👍」を押せるようにします。
- Supabaseで「likes」テーブルを作成
- user_id と post_id を紐付けて記録
- 投稿一覧を表示する際に「いいね数」を集計
これにより、人気投稿が一目でわかる仕組みが作れます。リアルタイム購読を組み合わせれば、いいねが押された瞬間にカウントが更新されます。
(2) スレッド(返信機能)
掲示板の投稿に対してコメントをつけられるようにします。
- replies テーブルを作成
- parent_post_id を持たせて階層構造を実現
- 表示時にツリー構造でレンダリング
UIは「折りたたみ」や「インデント表示」を使うと見やすくなります。
(3) 通知機能
「自分の投稿に返信がついたら通知する」仕組みを入れると、利用者の定着率が大幅に上がります。
- SupabaseのWebhookを使い、イベント発生時に通知処理を実行
- DiscordやSlackに通知を飛ばすことも可能
8. デプロイして公開する
掲示板が形になったら、いよいよ公開です。
(1) VercelでNext.jsをデプロイ
Next.jsを使うならVercelが最も簡単です。
- GitHubにコードをpush
- Vercelと連携し、環境変数にSupabaseのAPIキーを設定
- 自動でビルドされ、URLが発行される
(2) Supabaseはクラウドで管理
Supabaseはクラウドで稼働するので、特別なサーバー構築は不要です。Vercelと組み合わせれば、完全無料で使えるリアルタイム掲示板を公開できます。
(3) 独自ドメインを設定
本格的に運営する場合は、独自ドメインを取得してVercelに設定しましょう。
9. 今後の発展アイデア
- モデレーション機能:不適切な投稿を管理者が削除できる
- AIサポート:投稿内容を自動要約、スパム検知
- マルチデバイス対応:PWA化してスマホアプリ風に
掲示板はシンプルなサービスですが、工夫次第で多様な機能を持たせられます。
10. まとめと学び
今回の記事では、Next.js×Supabaseを組み合わせてリアルタイム掲示板を作る流れを、実践的に紹介しました。改めてポイントを振り返ってみましょう。
- Next.jsでフロントエンドを構築
- SSRやISRを活かしつつ、Reactベースで快適なUIを提供できる
- API Routesを使えばサーバーレス的に処理を追加可能
- Supabaseでバックエンドをシンプルに実現
- 認証、データベース、リアルタイム通信が一括で利用可能
- PostgreSQLベースなのでスケーラブル
- フロントエンドと直結しやすいSDKが用意されている
- リアルタイム更新でユーザー体験を強化
- supabase.channel を利用した購読で即時更新を実現
- 投稿や「いいね」が即座に反映されることで、SNSのような体験に近づく
- デプロイまでスムーズに進められる
- Next.jsはVercelで簡単にホスティング可能
- Supabaseはクラウドサービスなので追加のサーバー不要
11. 今後の応用と可能性
今回作った掲示板はシンプルですが、拡張の幅は無限大です。たとえば:
- 企業内の社内掲示板として利用
- 学習コミュニティやイベント専用掲示板に展開
- AI機能を取り入れて、要約やスパム検知を自動化
- モバイルアプリ化して、PWAやReact Nativeと連携
特にSupabaseは、Postgresベースで高度なクエリやロジックを扱えるため、本格的なプロダクト開発にも耐えられます。
12. 最後に
「掲示板を作る」という題材は、一見シンプルですが、ユーザー管理・投稿・リアルタイム更新・デプロイといったWebアプリ開発の核心的な要素が詰まっています。
Next.jsとSupabaseを使えば、これまで複雑だったバックエンド処理をシンプルにまとめつつ、実践的なサービスを短期間で構築できます。
ぜひ今回の内容を足掛かりにして、
- 自分専用のSNS
- 学習コミュニティのプラットフォーム
- ビジネス向けの情報共有ツール
といったオリジナルサービスを開発してみてください。
コメント