モダンな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_URLNEXT_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(最小実行可能製品)の開発
 - 個人プロジェクト
 - プロトタイプの作成
 - 小規模なビジネスアプリ
 
まずは小さく始めて、成長に合わせて段階的にスケールアップしていく戦略が取れるのが最大の魅力です。
今すぐ始めてみましょう!