モダンなWebサービスを作りたいけど、できるだけお金をかけたくない。そんな方におすすめなのが、Next.js + Vercel + Supabaseの組み合わせです。この3つのツールを使えば、完全無料でフルスタックのWebアプリケーションを構築できます。
なぜこの組み合わせが最強なのか
無料枠が充実している
- Next.js: フロントエンドフレームワーク(無料)
- Vercel: ホスティング・デプロイ(Hobbyプランは無料)
- Supabase: データベース・認証・リアルタイム機能(無料枠あり)
開発効率が良い
- Next.jsの豊富な機能(SSR、API Routes、最適化)
- Vercelの自動デプロイ
- Supabaseの即座に使えるバックエンド機能
実際の構築手順
ステップ1: Next.jsプロジェクトの作成
まずはNext.jsプロジェクトを作成しましょう。
npx create-next-app@latest my-app
cd my-app
TypeScriptを使う場合(推奨):
npx create-next-app@latest my-app --typescript
cd my-app
ステップ2: Supabaseの設定
Supabaseプロジェクトの作成
- Supabaseにアクセス
- GitHubアカウントでサインアップ
- 「New project」をクリック
- プロジェクト名とパスワードを設定
- リージョンを選択(日本の場合は
Northeast Asia (Tokyo)
推奨)
環境変数の設定
プロジェクト作成後、Supabaseの管理画面で以下の情報を取得:
# .env.local
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
Supabaseクライアントのインストール
npm install @supabase/supabase-js
Supabaseクライアントの設定
// lib/supabase.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)
ステップ3: データベースのテーブル作成
Supabaseの管理画面のSQL Editorで以下を実行:
-- ユーザープロフィールテーブル
create table profiles (
id uuid references auth.users on delete cascade,
updated_at timestamp with time zone,
username text unique,
full_name text,
avatar_url text,
website text,
primary key (id),
unique(username),
constraint username_length check (char_length(username) >= 3)
);
-- RLS (Row Level Security) を有効化
alter table profiles enable row level security;
-- ポリシーの設定
create policy "Public profiles are viewable by everyone."
on profiles for select
using ( true );
create policy "Users can insert their own profile."
on profiles for insert
with check ( auth.uid() = id );
create policy "Users can update own profile."
on profiles for update
using ( auth.uid() = id );
ステップ4: 認証機能の実装
認証コンポーネントの作成
// components/Auth.jsx
import { useState } from 'react'
import { supabase } from '../lib/supabase'
export default function Auth() {
const [loading, setLoading] = useState(false)
const [email, setEmail] = useState('')
const handleLogin = async (email) => {
try {
setLoading(true)
const { error } = await supabase.auth.signInWithOtp({ email })
if (error) throw error
alert('Check your email for the login link!')
} catch (error) {
alert(error.error_description || error.message)
} finally {
setLoading(false)
}
}
return (
<div className="row flex flex-center">
<div className="col-6 form-widget">
<h1 className="header">Supabase + Next.js</h1>
<p className="description">Sign in via magic link with your email below</p>
<div>
<input
className="inputField"
type="email"
placeholder="Your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<button
onClick={(e) => {
e.preventDefault()
handleLogin(email)
}}
className="button block"
disabled={loading}
>
{loading ? <span>Loading</span> : <span>Send magic link</span>}
</button>
</div>
</div>
</div>
)
}
メインアプリケーションの実装
// pages/index.js
import { useState, useEffect } from 'react'
import { supabase } from '../lib/supabase'
import Auth from '../components/Auth'
import Account from '../components/Account'
export default function Home() {
const [session, setSession] = useState(null)
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session)
})
supabase.auth.onAuthStateChange((_event, session) => {
setSession(session)
})
}, [])
return (
<div className="container" style={{ padding: '50px 0 100px 0' }}>
{!session ? <Auth /> : <Account key={session.user.id} session={session} />}
</div>
)
}
ステップ5: Vercelへのデプロイ
GitHubリポジトリの作成
- GitHubで新しいリポジトリを作成
- ローカルのプロジェクトをpush
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/yourusername/your-repo.git
git push -u origin main
Vercelでのデプロイ設定
- Vercelにアクセス
- GitHubアカウントでサインアップ
- 「New Project」をクリック
- GitHubリポジトリを選択
- 環境変数を設定:
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
- 「Deploy」をクリック
実践的なTips
1. 環境変数の管理
開発環境と本番環境で異なる設定が必要な場合:
# .env.local (開発用)
NEXT_PUBLIC_SUPABASE_URL=your-dev-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-dev-supabase-anon-key
# .env.production (本番用)
NEXT_PUBLIC_SUPABASE_URL=your-prod-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-supabase-anon-key
2. パフォーマンス最適化
Next.jsの画像最適化を活用:
import Image from 'next/image'
function ProfileImage({ src, alt }) {
return (
<Image
src={src}
alt={alt}
width={200}
height={200}
priority
/>
)
}
3. SEO対策
Next.jsのHeadコンポーネントを使用:
import Head from 'next/head'
function MyPage() {
return (
<>
<Head>
<title>My App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
{/* コンテンツ */}
</main>
</>
)
}
4. エラーハンドリング
Supabaseのエラーを適切に処理:
const handleSubmit = async (formData) => {
try {
const { data, error } = await supabase
.from('your_table')
.insert(formData)
if (error) throw error
// 成功時の処理
console.log('Data inserted:', data)
} catch (error) {
console.error('Error:', error.message)
// ユーザーにエラーメッセージを表示
}
}
無料枠の制限と対策
Vercel Hobbyプランの制限
- 月間100GBの帯域幅
- 月間100回のサーバーレス実行
- カスタムドメインは1つまで
Supabase無料枠の制限
- 2つのプロジェクトまで
- 500MBのデータベースストレージ
- 月間50,000回のAPI呼び出し
スケールアップ時の対策
サービスが成長したら段階的に有料プランに移行:
- まずはVercelのProプラン(月$20)
- SupabaseのProプラン(月$25)
- 必要に応じてカスタムプラン
まとめ
Next.js + Vercel + Supabaseの組み合わせなら、初期費用ゼロでモダンなWebサービスを構築できます。特に以下のような場面で威力を発揮します:
- MVP(最小実行可能製品)の開発
- 個人プロジェクト
- プロトタイプの作成
- 小規模なビジネスアプリ
まずは小さく始めて、成長に合わせて段階的にスケールアップしていく戦略が取れるのが最大の魅力です。
今すぐ始めてみましょう!