🌟

【Vercel】【Terraform】Next.jsアプリをデプロイしてみる

2025/01/05に公開

Next.js で作ったアプリを Vercel へデプロイしてみます。

今回は Vercel のコンソールではなく、Terraformを使用して構築していきます

Vercel コンソールでの設定方法はこちら

https://hisuiblog.com/nextjs-vercel-deploy/

Vercel とは??

公式 HP

https://vercel.com/

Vercel とは、ゼロコンフィグで WEB アプリケーションをデプロイできるサービスです。

Angular、React、Vue など様々なフレームワークに対応しています。

特に、サービスの提供元である Vercel 社が開発してるNext.jsを簡単にデプロイできます。

なんと、GitHub 等のリポジトリを連携するだけでデプロイでき、

PR をもとにアプリのプレビューを作成したり、自動デプロイが可能です!

本記事のゴール

  • Next.js のアプリを作成し、Vercel にデプロイする。
  • ブラウザからアクセスできることを確認する
  • 自動デプロイできることを確認する。

前提

想定読者

  • Node.js がインストールされている
  • Next.js について詳細な解説がなくても大丈夫
  • GitHub のアカウントがある
  • Terraform が使える

本記事で使用しているバージョン

~$ npx -version
9.8.1
~$ npx create-next-app --version
13.4.13
~$ terraform -v
Terraform v1.4.2

参考記事

手順が公式ドキュメントにあったので、それを参考にします

https://vercel.com/guides/integrating-terraform-with-vercel

また、Terraform の公式ドキュメントや Zenn の記事も参考にして、進めていきます。

https://registry.terraform.io/providers/vercel/vercel/latest/docs

https://zenn.dev/keita_hino/articles/3044d2af6dec61

Next.js のアプリケーション

アプリケーション作成

https://vercel.com/templates/next.js/blog-starter-kit

こちらのテンプレートを使用してデプロイするアプリを作成します!

// アプリ作成
~$ npx create-next-app --example blog-starter sample-blog-nextjs-app
Creating a new Next.js app in *********/sample-blog-nextjs-app.

Downloading files for example blog-starter. This might take a moment.

Installing packages. This might take a couple of minutes.


added 215 packages, and audited 216 packages in 48s

89 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Initialized a git repository.

Success! Created sample-blog-nextjs-app at *********/sample-blog-nextjs-app
Inside that directory, you can run several commands:

  npm run dev
    Starts the development server.

  npm run build
    Builds the app for production.

  npm start
    Runs the built app in production mode.

We suggest that you begin by typing:

  cd sample-blog-nextjs-app
  npm run dev

作成出来たら、動作確認しておきましょう

// ディレクトリ移動
~$ cd sample-blog-nextjs-app

// アプリを起動
sample-blog-nextjs-app$ npm run dev

> dev
> next

- ready started server on 0.0.0.0:3000, url: http://localhost:3000
- event compiled client and server successfully in 191 ms (18 modules)
- wait compiling / (client and server)...
- event compiled client and server successfully in 1948 ms (301 modules)
- wait compiling /posts/[slug]...
- event compiled client and server successfully in 355 ms (324 modules)
^C

sample-blog-nextjs-app$

ブラウザから、http://localhost:3000にアクセスして下記が表示されれば OK!

確認ができたら、Ctrl + c でアプリを停止させましょう。

GitHub のリポジトリを作成

https://github.com/new

この画面でリポジトリを作成します。

GitHub へ push

リポジトリの画面を参考に Git へ push します。

sample-blog-nextjs-app$ git remote add origin https://github.com/********/sample-blog-nextjs-app.git
sample-blog-nextjs-app$ git branch -M main
sample-blog-nextjs-app$ git push -u origin main
Enumerating objects: 73, done.
Counting objects: 100% (73/73), done.
Delta compression using up to 16 threads
Compressing objects: 100% (65/65), done.
Writing objects: 100% (73/73), 308.55 KiB | 11.02 MiB/s, done.
Total 73 (delta 6), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (6/6), done.
To https://github.com/********/sample-blog-nextjs-app.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

Vercel での事前準備

サインアップ

https://vercel.com/signup

アカウントがない方は、こちらからサインアップしていきます。

今回は試しにデプロイしてみるだけなので、プランは「Hobby」※無料を選択します。

アカウント名を入力したら、Continue をクリックし次に進みます。

GitHub のリポジトリを使用したいので、「Continue with GitHub」を選択

Vercel から GitHub をアクセスできるよう、「Authorize Vercel」をクリックします

アカウントの作成が完了し、ホーム画面(?)に遷移します

Vercel から GitHub へアクセスできるようにする

ホーム画面にて、

Import Git Repository > Select a Git Namespace > Add GitHub Accountを選択

今回は、先ほど作成した GitHub リポジトリのみを Import していきます。

Only select repositories」を選び、Select repositories にて GitHub リポジトリを選択。

選択できたら、Installをクリックします。

GitHub のパスワードを入力すると、ホーム画面に遷移しリポジトリが表示されていれば OK!

Token を発行する

Terraform から Vercel へアクセスできるようToken を発行しておきます。

手順は公式ドキュメントを参考にします。

https://vercel.com/guides/how-do-i-use-a-vercel-api-access-token

https://vercel.com/account/tokens

こちらにアクセスし、Token を発行していきます。

入力情報は下記を参考にし、Createをクリックします。

プロパティ 説明
TOKEN NAME Tokenの名前。 わかりやすいものを設定。 VERCEL_API_TOKEN
SCOPE Tokenの権限。 絞ったほうがいいが、今回はフルでつける。 Full Account
EXPIRATION Tokenの有効期限。 セキュリティ的には設定したほうが良いが、今回は期限なし。 No Expiration

Token が表示されるため、メモしておきます。後ほど使います!

※後から Token の値を確認できないため、注意

これで事前準備は完了しました!なので、Terraform でコードを書いていきます。

Terraform

ファイルは次のものを作成しました

.
├── deployment.tf
├── main.tf
├── project.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf

コード

main.tf

Vercel を使うことを定義します。

terraform {
  required_providers {
    vercel = {
      source  = "vercel/vercel"
      version = "~> 0.4"
    }
  }
}

provider.tf

Vercel 固有の設定をしておきます。今回は先ほど取得した Token を設定します。

Token の値を直書きするのはよくないので、変数を読み取ります。

実際の値は、後ほど出てくる terraform.tfvars に記述します。

provider "vercel" {
  api_token = var.vercel_api_token
}

variables.tf

使う変数を定義します。Vercel Token の変数を用意しておきます。

variable "vercel_api_token" {}

terraform.tfvars

ここで、Vercel の Token の値を定義します。

# Tokenの値に置き換えてください
vercel_api_token = "<Tokenの値>"

Git で管理する場合、このファイルだけはコミットしないよう注意してください!

project.tf

Vercel に作成する Project を定義します

resource "vercel_project" "example" {
  name      = "sample-blog-nextjs-app"
  framework = "nextjs"

  git_repository = {
    type = "github"
    # ユーザー名/リポジトリ名は置き換えてください
    repo = "<ユーザー名/リポジトリ名>"
  }
}
プロパティ 説明
name プロジェクト名。自分がわかりやすいものなら何でもいい。
framework アプリのフレームワーク。
git_repository 連携させるリポジトリを定義。
type GitHub、GitLab、BitBucket のどれと連携させるか。
repo 連携させるリポジトリ。

deployment.tf

デプロイの内容を定義します。

特別なデプロイ設定は今回しないので、これぐらいのプロパティで OK です!

resource "vercel_deployment" "example" {
  project_id  = vercel_project.example.id
  ref        = "main"
  production  = true
}
プロパティ 説明
project_id デプロイするプロジェクトのID
ref デプロイ対象のブランチやコミット。 GitHub、GitLab、BitBucket からデプロイさせる場合は必須。
production 本番環境かどうか

init

~$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding vercel/vercel versions matching "~> 0.4"...
- Installing vercel/vercel v0.15.0...
- Installed vercel/vercel v0.15.0 (signed by a HashiCorp partner, key ID ********)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

plan

~$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # vercel_deployment.example will be created
  + resource "vercel_deployment" "example" {
      + domains    = (known after apply)
      + id         = (known after apply)
      + production = true
      + project_id = (known after apply)
      + ref        = "main"
      + team_id    = (known after apply)
      + url        = (known after apply)
    }

  # vercel_project.example will be created
  + resource "vercel_project" "example" {
      + framework                               = "nextjs"
      + git_repository                          = {
          + production_branch = (known after apply)
          + repo              = "*******/sample-blog-nextjs-app"
          + type              = "github"
        }
      + id                                      = (known after apply)
      + name                                    = "sample-blog-nextjs-app"
      + protection_bypass_for_automation_secret = (known after apply)
      + serverless_function_region              = (known after apply)
      + team_id                                 = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

apply

~$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # vercel_deployment.example will be created
  + resource "vercel_deployment" "example" {
      + domains    = (known after apply)
      + id         = (known after apply)
      + production = true
      + project_id = (known after apply)
      + ref        = "main"
      + team_id    = (known after apply)
      + url        = (known after apply)
    }

  # vercel_project.example will be created
  + resource "vercel_project" "example" {
      + framework                               = "nextjs"
      + git_repository                          = {
          + production_branch = (known after apply)
          + repo              = "*******/sample-blog-nextjs-app"
          + type              = "github"
        }
      + id                                      = (known after apply)
      + name                                    = "sample-blog-nextjs-app"
      + protection_bypass_for_automation_secret = (known after apply)
      + serverless_function_region              = (known after apply)
      + team_id                                 = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

vercel_project.example: Creating...
vercel_project.example: Creation complete after 1s [id=prj_****************************]
vercel_deployment.example: Creating...
vercel_deployment.example: Still creating... [10s elapsed]
vercel_deployment.example: Still creating... [20s elapsed]
vercel_deployment.example: Still creating... [30s elapsed]
vercel_deployment.example: Still creating... [40s elapsed]
vercel_deployment.example: Creation complete after 49s [id=dpl_****************************]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

エラーが出なければ OK です!

ブラウザからアクセスして動作確認

https://vercel.com/<アカウント名>/<プロジェクト名> ※アカウント名、プロジェクト名は各々

上記のような URL から Vercel のダッシュボードに遷移し、右上の Visitをクリックします

下記のように表示されれば OK です!

自動デプロイ

commit

テスト用のブランチ(test)を切り、checkout します

sample-blog-nextjs-app$ git checkout -b test
Switched to a new branch 'test'
sample-blog-nextjs-app$ git branch
  main
* test

components/intro.tsxに少し変更を加えます(ハイライト部)

import { CMS_NAME } from '../lib/constants'

const Intro = () => {
  return (
    <section className="flex-col md:flex-row flex items-center md:justify-between mt-16 mb-16 md:mb-12">
      <h1 className="text-5xl md:text-8xl font-bold tracking-tighter leading-tight md:pr-8">
        Auto Deploy Test Success!!
      </h1>
      <h4 className="text-center md:text-left text-lg mt-5 md:pl-8">
        A statically generated blog example using{' '}
        <a
          href="https://nextjs.org/"
          className="underline hover:text-blue-600 duration-200 transition-colors"
        >
          Next.js
        </a>{' '}
        and {CMS_NAME}.
      </h4>
    </section>
  )
}

export default Intro

commit および push します

sample-blog-nextjs-app$ git add .
sample-blog-nextjs-app$ git commit -m"test_commit"
[test a92755f] test_commit
 1 file changed, 1 insertion(+), 1 deletion(-)
sample-blog-nextjs-app$ git push origin test
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 16 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 385 bytes | 385.00 KiB/s, done.
Total 4 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
remote:
remote: Create a pull request for 'test' on GitHub by visiting:
remote:      https://github.com/********/sample-blog-nextjs-app/pull/new/test
remote:
To https://github.com/********/sample-blog-nextjs-app.git
 * [new branch]      test -> test

PR を作成

GitHub のリポジトリの画面から PR を作成していきます

Compare & pull requestをクリックします

適当にコメントして、Create pull requestをクリックし、PR を作成します

Preview を確認

PR を作成すると、vercel の bot がコメントを残してくれます

そこからPR マージ後のプレビューを確認できます。

Visit Previewをクリックし、下記のように表示されれば OK です!

(Auto Deploy Test Success!! と表示されるはず。。。)

コメントを残せるなど、見るだけではなくレビューしやすいものとなっています

PR をマージ

プレビューにて確認できたので、PR をマージしていきます。

Merge pull request → Confirm mergeをクリックします。

マージ出来たら、Delete branch でマージ元のブランチを消しておきましょう

自動デプロイを確認

ダッシュボードの Visitからデプロイの結果を確認します。

Created が更新されていれば、デプロイが成功しています。

下記のように表示されれば OK です!

(Auto Deploy Test Success!! と表示されるはず。。。)

削除

~$ terraform destroy
vercel_project.example: Refreshing state... [id=prj_****************************]
vercel_deployment.example: Refreshing state... [id=dpl_****************************]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # vercel_deployment.example will be destroyed
  - resource "vercel_deployment" "example" {
      - domains    = [
          - "sample-blog-nextjs-app.vercel.app",
          - "sample-blog-nextjs-app-*******.vercel.app",
          - "sample-blog-nextjs-app-git-main-*******.vercel.app",
        ] -> null
      - id         = "dpl_****************************" -> null
      - production = true -> null
      - project_id = "prj_****************************" -> null
      - ref        = "main" -> null
      - url        = "sample-blog-nextjs-8ab8svfsc-*******.vercel.app" -> null
    }

  # vercel_project.example will be destroyed
  - resource "vercel_project" "example" {
      - framework                  = "nextjs" -> null
      - git_repository             = {
          - production_branch = "main" -> null
          - repo              = "*******/sample-blog-nextjs-app" -> null
          - type              = "github" -> null
        } -> null
      - id                         = "prj_****************************" -> null
      - name                       = "sample-blog-nextjs-app" -> null
      - serverless_function_region = "iad1" -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

vercel_deployment.example: Destroying... [id=dpl_****************************]
vercel_deployment.example: Destruction complete after 0s
vercel_project.example: Destroying... [id=prj_****************************]
vercel_project.example: Destruction complete after 0s

Destroy complete! Resources: 2 destroyed.

まとめ

すごい簡単にデプロイできましたー!!

さらに

  • カスタムドメインを使用する
  • スピードインサイトを有効にする

などをしていきたいと思いますー。

Discussion