2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Better-T-StackでNextjs×Honoのモノレポ構成アプリケーションを作る方法

Posted at

はじめに

Better-T-Stackを利用して、Next.jsとHonoを組み合わせたモノレポ構成のアプリケーション環境を作る方法を説明していきます。

本記事で説明するアプリケーション環境は、フロント側にNext.jsのApp Router、バックエンド側にHonoフレームワークを使用し、フロントはVercelにバックエンドはCloudflareにデプロイします。モノレポ構成に使用するパッケージマネージャーはpnpm、ビルドツールはTurborepoを使用します。SupabaseやTursoといったデータベースとの連携については、本記事では取り扱いませんのでご注意ください。

Better-T-Stackとは

Better-T-Stackは、エンドツーエンドの型安全性(End-to-End Type-Safe)を備えたTypeScriptプロジェクトを、自分に必要な機能だけを選んで環境構築できる、最新のCLIツールです。

Philosophy

  • Roll your own stack: pick only what you need, nothing extra.
  • Minimal templates: bare-bones scaffolds with zero bloat.
  • Latest dependencies: always current and stable by default.
  • Free and open source: forever.
    https://www.better-t-stack.dev/docs

引用にもあるように最新技術を使った型安全な環境を、肥大化させずにゼロから自由に組み立てられるツールと言えます。

次のコマンドで始めることができ、実行するとフロントやバックエンド、そしてDBや各種ランタイムの選択がターミナルを通して対話形式で選べます。

Quick Start
# Using bun (recommended)
bun create better-t-stack@latest

# Using pnpm
pnpm create better-t-stack@latest

# Using npm
npx create-better-t-stack@latest

良い点として、いちいちフレームワークとフレームワークの繋ぎこみや設定ファイルなどの作成を行わず、スピーディーにアプリの環境を構築できます。Webだけではなく、ネイティブアプリの環境作成にも対応しており、マルチプラットフォームの環境作りにも利用することができます。

難点として、Quick Startを実行しても、選択したフレームワークやオプションの組み合わせによってはビルドエラーが発生する場合があります。ゼロスタートはすごく早いのですが、意外にもその後に必要な加筆修正があるので、詰まりがちな修正点を説明して行きたいと思います。

Quick Start

次の環境で作成していきます。

  • Select project type: Web
  • frontend: Next.js
  • backend hono
  • runtime: Cloudflare Workers
  • DB : None
  • API Type : tRPC
  • authentication provider : None
  • addons : Turborepo, Biome
  • Include Examples : None
  • Web deployment: None
  • Choose package Manager: pnpm

このコマンドを実行すると、上記の選択をスキップして実行できます。

ショートカット
pnpm create better-t-stack@latest my-app --frontend next --backend hono --runtime workers --database none --orm none --api trpc --auth none --payments none --addons turborepo biome --examples none --db-setup none --web-deploy none --server-deploy cloudflare --git --package-manager pnpm --install

作成したアプリのディレクトリに移動

ディレクトリ移動
cd my-app

生成されたディレクトリ構成

/
├── apps/
│   ├── server/                  # Hono + Cloudflare Workers バックエンド
│   │   ├── src/
│   │   │   └── index.ts         # Honoアプリ エントリーポイント
│   │   ├── .env
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── tsdown.config.ts
│   │
│   └── web/                     # Next.js フロントエンド
│       ├── src/
│       │   ├── app/             # Next.js App Router
│       │   │   ├── layout.tsx
│       │   │   └── page.tsx
│       │   ├── components/      # UIコンポーネント
│       │   │   ├── ui/          # shadcn/ui コンポーネント
│       │   │   ├── header.tsx
│       │   │   ├── providers.tsx
│       │   │   └── theme-provider.tsx
│       │   ├── lib/             # ユーティリティ
│       │   └── utils/
│       │       └── trpc.ts      # tRPCクライアント設定
│       ├── .env
│       ├── components.json
│       └── package.json
│
├── packages/
│   ├── api/                     # tRPC API定義(共有)
│   │   ├── src/
│   │   │   ├── routers/         # tRPCルーター
│   │   │   ├── context.ts       # tRPCコンテキスト
│   │   │   └── index.ts
│   │   └── package.json
│   │
│   ├── config/                  # 共有設定
│   │   ├── tsconfig.base.json   # 共通TypeScript設定
│   │   └── package.json
│   │
│   ├── env/                     # 環境変数管理
│   │   ├── src/
│   │   │   ├── server.ts        # サーバー用env(Cloudflare Workers)
│   │   │   └── web.ts           # Web用env(t3-oss/env-nextjs)
│   │   ├── env.d.ts             # Cloudflare環境の型定義
│   │   └── package.json
│   │
│   └── infra/                   # インフラ設定(Alchemy)
│       ├── alchemy.run.ts       # Cloudflare Workersデプロイ設定
│       ├── .env
│       └── package.json
│
├── biome.json                   # Biome(リンター/フォーマッター)設定
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml          # pnpmワークスペース設定
├── tsconfig.json
└── turbo.json                   # Turborepoタスク設定

以上でBetter-T-StackのQuickStartは終了です。このままだと、ビルドエラーが起きるので次は修正点について説明していきます。

エラー修正

試しに、ビルドしてみましょう。Better-T-StackV3.17.0時点の現在はエラーが出ると思います。

ビルドを実行
pnpm run build
エラーメッセージ
../../packages/api/src/context.ts:1:45
Type error: Cannot find module 'hono' or its corresponding type declarations.

> 1 | import type { Context as HonoContext } from "hono";
    |                                             ^
  2 |
  3 | export type CreateContextOptions = {
  4 |   context: HonoContext;

packages/apiがHonoを依存関係として持っていないにもかかわらず、Honoをimportしてるため発生しています。
apps/serverがHonoを依存関係として持っているのですが、pnpm-workspace機能を利用して、一括管理しましょう。

1. pnpm-workspace.yamlにHonoを追加

pnpm-workspace.yaml
  "@trpc/client": ^11.7.2
  "hono": "^4.8.2 #  追記

2. apps/server/package.jsonpackages/api/package.jsonにhonoを追加する

server/package.json
"dependencies": {
    "@hono/trpc-server": "^0.4.0",
    "@trpc/server": "catalog:",
    "@utsushimi-nikki/api": "workspace:*",
    "@utsushimi-nikki/db": "workspace:*",
    "@utsushimi-nikki/env": "workspace:*",
    "dotenv": "catalog:",
    "hono": "catalog:", //  バージョン指定されているのを`catalog:`に変更
    "zod": "catalog:"
  }
packages/api/package.json
"dependencies": {
    "@trpc/client": "catalog:",
    "@trpc/server": "catalog:",
    "@types/pg": "catalog:",
    "@utsushimi-nikki/db": "workspace:*",
    "@utsushimi-nikki/env": "workspace:*",
    "dotenv": "catalog:",
    "drizzle-orm": "catalog:",
    "zod": "catalog:",
    "hono": "catalog:"
  }

3. パッケージを更新してビルドを実行

pnpm install

先程のビルドエラーは出なくなっているはずです。

ビルド実行
pnpm run build
ビルドタスク成功メッセージ
 Tasks:    2 successful, 2 total
Cached:    0 cached, 2 total
  Time:    7.675s 

以上で、エラー修正は終了です。

Alchemyの設定

Better-T-Stackはサーバー側のモジュールをCloudflareにデプロイするにあたりAlchemyを利用しています。初回設定は自分で行う必要があるので設定していきましょう。

Alchemyとは

Alchemy is a TypeScript library that creates and manages cloud infrastructure when you run it. Instead of using opinionated CLIs or configuration files, you write and run a regular TypeScript program.
https://alchemy.run/what-is-alchemy/

引用にあるように、TypeScriptでクラウドの管理・構築ができるライブラリです。一言で言えば、TypeScriptで記述するIaC(Infrastructure as Code)ツールです。
alchemy.run.tsといったファイルにインフラ定義を書き、実行するだけでリソースの作成・削除・更新ができます。

設定手順

こちらに記載されている手順を元にして行います。

Alchemyコマンドのスクリプト設定

Alchemy自体は、既にpackages/infraモジュールにインストールされていますが、このディレクトリでしかalchemyコマンドは実行できません。いちいち移動して実行するのが手間なので、ルートのpackage.jsonにscriptsを記載して楽にします。

package.json
    "scripts": {
        "alchemy": "pnpm -F @utsushimi-nikki/infra exec alchemy"
    }

Alchemyのパスワードの変更

packages/infra以下の.envファイルに、Alchemyのパスワードが記載されています。各自決めた新しいパスワードを設定しましょう。

.env
ALCHEMY_PASSWORD=please-change-this

Configure your Profile

pnpm run alchemy configure

┌  🧪 Configure Profile
│
◇  Enter profile name
│  default
│
◇  Select a login method for Cloudflare
│  OAuth
│
◇  Customize scopes?
│  No
│
◇  Opening browser to authorize with Cloudflare...
│  
│
└  ✅ Configured profile default

とりあえずでやるなら初回提示されている選択肢でいいと思います。

  • Profile name : Alchemyが認証情報を保存する際に使用する名前
  • login method for Cloudflare: Cloudflareに認証する方法
  • Scope : デプロイ時に必要とする権限設定

OAuthの場合、URLがターミナルに表示されるのでクリックしてURL先で連携を承認してください。認証が成功すると以下の画面が表示されると思います。

スクリーンショット 2026-01-17 235107.png

Login to Cloudflare

すでにConfigure Profileでログインしているのでスキップでいいと思います。一応実行すると上書きするか聞いてくるのでNoを選択します。

pnpm run alchemy login

┌  🧪 Login
│
◇  You are already logged in to cloudflare on profile "default".
│
◇  Would you like to overwrite?
│  No
└  Operation cancelled.

以上でAlchemyの初回設定は完了です。もし、パスワードを変更したい場合は.envで変更した後に.alchemyフォルダを全て削除してConfigure Profileからやり直してください。

サーバー側の起動スクリプト修正

Better-T-Stackが初回生成するサーバー起動のスクリプトがAlchemyを利用していないため、ルートpackage.jsonを修正します。

package.json
    "scripts": {
        "dev:server": "turbo -F server dev",
    }
     次に変更
    "scripts": {
        "dev:server": "turbo -F @my-app/infra dev"
    }

修正したサーバースクリプトを実行し、サーバーを起動してください。http://localhost:3000 にアクセスしてOKの文字が表示されたら成功です。

また、webモジュールも同時に起動して確認しましょう。http://localhost:3001 にアクセスしてAPIStatusにConnectedが表示されれば問題ないです。

# Server
pnpm run dev:server

# Web+Server
pnpm run dev

デプロイ

環境別に読み込むenvファイルを変える

今のままだと、デプロイする際に使用するenvファイルが開発環境のままになってしまいます。新たに本番環境用のenvファイル.env.productionapps/server以下に作成してください。値はWeb側をVercelにデプロイしない限り確定しないのでそのままで良いです。

.env.production
CORS_ORIGIN=http://localhost:3001

次に、packages/infra/package.jsonのスクリプトを修正します。開発サーバーを起動するコマンドには.envをデプロイ・デストロイするコマンドには.env.productionを渡します。

    "scripts": {
        "dev": "alchemy dev --env-file ../../apps/server/.env",
        "deploy": "alchemy deploy --env-file ../../apps/server/.env.production",
        "destroy": "alchemy destroy --env-file ../../apps/server/.env.production"
    }

最後にpackages/infra/alchemy.run.tsの不要なenvファイル読み込みを削除します。

alchemy.run.ts
config({ path: "./.env" });
config({ path: "../../apps/server/.env" }) // ← 削除

Alchemyによるデプロイ設定

まず、設定をする前にVercelのアクセストークンを取得してください。↓から取得できます。アカウントがない場合は新規作成してから行ってください。

取得したアクセストークンをpackages/infra/.envに追記してください。

.env
VERCEL_ACCESS_TOKEN=取得したアクセストークン

次にpackages/infra/alchemy.run.tsにVercelのデプロイ設定を追加してください。
githubのアカウント名を控えるのと、アプリをgithubにpushしてリポジトリを作成している必要があります。

alchemy.run.ts
const app = await alchemy("my-app");

export const server = await Worker("server", {
// 省略
});

export const web = await Project("web", {
    name: "vercelダッシュボードに表示されるアプリ名",
    framework: "nextjs",
    rootDirectory: "apps/web",
    buildCommand: "pnpm run build",
    installCommand: "pnpm install --frozen-lockfile",
    environmentVariables: [
        {
            key: "NEXT_PUBLIC_SERVER_URL",
            target: ["production", "preview"],
            // biome-ignore lint/style/noNonNullAssertion: server.url is always defined after deployment
            value: server.url!, // Cloudflare WorkerのURLを自動参照
        },
    ],
    gitRepository: {
        type : "github",
        repo : "githubのユーザ名/リモートリポジトリの名前"
    }
});

設定を終えたら、デプロイを行いましょう。

デプロイを実行
pnpm run deploy

Alchemyによってバックエンド側はCloudflareにデプロイ出来たと思います。ターミナルに表示されたURLをクリックしてデプロイ出来ているか確認してください。OKが表示されていれば成功です。

Vercelにデプロイする

先程のデプロイ実行では不完全です。Vercelにコードのアップロードとビルドを行うには、プッシュするか既にpushするものがない場合はVercelのプロジェクトダッシュボードに行き、デプロイをする必要があります。

Vercelにアクセスしてダッシュボードから自分のアプリ名を探す

image.png

Developmentタブにアクセスし、Deploymentを作成する

image.png

ブランチはmainを選択して、Create Deploymentをクリック

image.png

Domain URLをコピーする

デプロイが出来たら、デプロイしたアプリのURLを取得しましょう。これは、バックエンド側がフロントとやり取りをする際に必要です。取得したら先程の.env.productionでそのまま変更していなかったCORS_ORIGIN_URLに設定します。

Overviewタブに行き、以下の画像にあるDomainsの部分にあるURLをコピーします。Deploymentの方でないので気をつけてください

スクリーンショット 2026-01-18 030023.png

.env.production
# 環境変数を更新する
CORS_ORIGIN=Domains

バックエンド側の環境変数を更新するため、再度Alchemyを利用してデプロイします。

pnpm run deploy

以上でデプロイは終了です。最後にフロント側のURLにアクセスして以下のようにConnectedが表示されているなら、動作成功です。お疲れ様でした。

image.png

まとめ

本記事では、Better-T-Stackを利用してNext.jsHonoを組み合わせたアプリケーションの構築方法を解説しました。DBの連携は行っていないですがBetter-T-StackSupabaseTursoといったBaaSも連携してくれるので試してみるといいかもしれません。
今回の技術スタックは無料で構築できるデプロイ環境なので、個人開発やとりあえずで動かすといった小さなアプリケーションで採用してみるのはありかもしれません。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?