個人で関わっているプロジェクトで、モノレポでフロントエンドアプリケーションを2つ管理(ver2とver3)しており、vercelで登録しているネームサーバーを使い回しながら最新版のアプリケーションをstagingにvercelにデプロイする必要がありました。
しかし、vercelのGithub連携ではルートディレクトリが1つしか設定できないのに加えて、環境変数ごとにルートディレクトリを切り替えることができないため、CDを回すことが困難でした。
今回はその問題をGithubActionsで解決してみました。
Actionsを組む
トークンを作成する
Vercelで使用するためのアクセストークンを作成します。
作成したらGithubのリポジトリにsecretsを以下のように設定します。

ID等を調べる
トークン以外にも2つシークレットに設定する必要があるのでそちらを調査します。
設定する内容は以下のようになっています。
| 名前 | 概要 |
|---|---|
| PROJECT_ID | プロジェクトのsettingsにあるID |
| ORG_ID | TeamのsettingsにあるTeamIDのこと |
workflowを組んでみる
今回vercelにデプロイするにあたって、ドメインは無料で準備できましたが、vercelで使える環境変数はHobbyプランだと準備できなかったので、ドメインでstgがprdかを区別しようと思います。
| 環境 | ドメイン |
|---|---|
| production | monorepo-deploy-vercel.vercel.app |
| staging | stg-monorepo-deploy-vercel.vercel.app |
以下workflowです。
- prdリリース用
name: deploy
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./yarn
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
- name: Install dependencies
run: yarn install
- name: install vercel CLI
run: yarn global add vercel
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel (production)
id: vercel_deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
output=$(vercel --token $VERCEL_TOKEN)
echo "$output"
echo "url=$output" >> $GITHUB_OUTPUT
- name: set Vercel Alias
run: |
vercel alias set ${{ steps.vercel_deploy.outputs.url }} monorepo-deploy-vercel.vercel.app --token=${{ secrets.VERCEL_TOKEN }}
- stgリリース用
name: deploy-stg.yml
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
push:
branches:
- develop
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./pnpm
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Install vercel CLI
run: pnpm install -g vercel
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel (preview)
id: vercel_deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
output=$(vercel --token $VERCEL_TOKEN)
echo "$output"
echo "url=$output" >> $GITHUB_OUTPUT
- name: set Vercel Alias
run: |
vercel alias set ${{ steps.vercel_deploy.outputs.url }} stg-monorepo-deploy-vercel.vercel.app --token=${{ secrets.VERCEL_TOKEN }}
outputs
各stepsで実行した内容はsteps.[id].outputs.[key]で参照することができます。
idはstepsで以下のように設定します。
- name: Deploy to Vercel (preview)
id: vercel_deploy
そこから出力させるために下のように$GITHUB_OUTPUTSを使用します。
下の場合、keyはoutput_${version}となります。
echo "output_${version}=${version}" >> "$GITHUB_OUTPUT"
1つのworkflowsファイルにまとめる
今回のworkflowsとしてはブランチごとに環境変数を設定して使いまわせるような形にしてみます。
インターン先でjsonを使って比較的綺麗に環境変数をまとめて使う方法を教えてもらったのでそちらを使いたいと思います。
workflows作成
name: deploy-for-vercel.yml
on:
workflow_call:
inputs:
environment:
required: true
type: string
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
ENV_JSON: | #デプロイする環境によって環境変数を変更する。
${{ toJson(
fromJson('{
"staging":{
"PM": "pnpm",
"DIRECTORY": "./pnpm",
"VERCEL_ENV": "preview",
"VERCEL_URL": "stg-monorepo-deploy-vercel.vercel.app"
},
"production":{
"PM": "yarn",
"DIRECTORY": "./yarn",
"VERCEL_ENV": "production",
"VERCEL_URL": "monorepo-deploy-vercel.vercel.app"
}
}')[inputs.environment]) }} #inputsでデプロイする環境を入力
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ fromJson(env.ENV_JSON).DIRECTORY }} #Jsonから文字列を取り出す
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version-file: ${{ fromJson(env.ENV_JSON).DIRECTORY }}/package.json
- name: Install pnpm
if: ${{ fromJson(env.ENV_JSON).DIRECTORY == './pnpm' }}
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
- name: Install dependencies
run: ${{ fromJson(env.ENV_JSON).PM }} install
- name: Install vercel CLI
run: |
if [ -f yarn.lock ]; then
yarn global add vercel
elif [ -f pnpm-lock.yaml ]; then
pnpm add -g vercel
fi
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=${{ fromJson(env.ENV_JSON).VERCEL_ENV }} --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel
id: vercel_deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
output=$(vercel --token $VERCEL_TOKEN)
echo "$output"
echo "url=$output" >> $GITHUB_OUTPUT
- name: Set Vercel Alias
run: |
vercel alias set ${{ steps.vercel_deploy.outputs.url }} ${{ fromJson(env.ENV_JSON).VERCEL_URL }} --token=${{ secrets.VERCEL_TOKEN }}
JSONの使い方
JSONを使うためにactionsで用意されてる関数を使用します。
| メソッド | 役割 |
|---|---|
| fromJson | 文字列をJSONにエンコード |
| toJson | JSONを文字列にデコード |
今回の場合は[でkeyを選択することで、ネストされているJSONを取り出しています。
${{ fromJSON(jsonString)[key] }}
そこからtoJsonを使って文字列に変換し、環境変数で設定できるようにしています。
JSONオブジェクトから文字列に変換することをシリアライズと言います。
ENV_JSON: | #デプロイする環境によって環境変数を変更する。
${{ toJson(
fromJson('{
"staging":{
"PM": "pnpm",
"DIRECTORY": "./pnpm",
"VERCEL_ENV": "preview",
"VERCEL_URL": "stg-monorepo-deploy-vercel.vercel.app"
},
"production":{
"PM": "yarn",
"DIRECTORY": "./yarn",
"VERCEL_ENV": "production",
"VERCEL_URL": "monorepo-deploy-vercel.vercel.app"
}
}')[inputs.environment]) }} #inputsでデプロイする環境を入力
workflowを使う
下のようなymlを書くことでworkflowsを使うことができます。
これはtriggerのような役割をして、どのブランチに対してpushやPRなどの特定の操作を行ったら、workflowsをどのような環境で使用するかを指定するかを定義できます。
name: deploy-stg.yml
on:
push:
branches:
- develop
jobs:
deploy:
uses: ./.github/workflows/deploy-for-vercel.yml
secrets: inherit #secretsを引き継ぐことができる
with:
environment: staging
workflowファイルはjobsでしか呼び出せないため、stepsには書かず、jobsに書いています。
また、workflowsにsecretsの情報を引き継ぐためにsecrets: inheritを記述しています。
最後に
結局、組織アカウントのプライベートリポジトリはGithubEnterprise等の課金をしてないとsecretsが使えないため上のやり方は断念しました。
チキショー
ただ、jsonの使い方は面白く使えるところが多いと思うのでぜひ参考にしてみてください。

