定期実行:Github Actions / Vercel cron / Cloudflare
2026年7月15日cron:定期的にコマンドやスクリプトを実行する仕組み
Github Actions
Githubのリポジトリから、またはローカルに
.github/workflows/フォルダを作成し.ymlファイルを作成workflows/フォルダには複数のymlファイルを置くことができる2,000分/月の実行時間まで可能
ymlファイル:認証キーで保護されたAPIルートを呼び出す設定
// cron.yml
name: cron-test
on:
schedule:
- cron: '*/10 * * * *' # 10分おき
workflow_dispatch:
jobs:
run-cron:
runs-on: ubuntu-latest
steps:
- name: Call API
run: |
curl -H "x-api-key: ${{ secrets.CRON_KEY }}" \
${{ vars.APP_BASE_URL }}/api/cron-test環境変数:
「リポジトリ/設定/Actions secrets and variables」から環境変数を設定
secretsとvariablesの使い分けはNextjsのNEXT_PUBLICと同じ感じで判断する。それに照らし合わせるとDB_URLやAPI_KEYはsecrets、BASE_URLはvariablesでいい
*secretsは再び環境変数の値を確認しようとしても表示されない
定期実行するAPIルート:
//route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(req: NextRequest) {
if (req.headers.get("x-api-key") !== process.env.CRON_KEY) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// 実行したい処理
console.log("Cron job running!");
return NextResponse.json({ status: "ok" });
}Vercel cron
"0 13 * * *":正確な時間(13:00)には実行されず、13 ~ 14時の間に実行される
vercel.json:ルートに置く。monorepoの場合は各appのルートに置く。
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [
{
"path": "/api/test-cron",
"schedule": "0 17 * * *"
}
]
}Githubの例と違い
vercel.jsonにはHTTPヘッダーは書けないので、VercelのダッシュボードにCRON_SECRETのような環境変数を作成し、該当ルートを保護する。
定期実行するAPIルート:
// route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(req: NextRequest) {
if (req.headers.get('authorization') !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
console.log("Vercel cron job running!");
return NextResponse.json({ status: "ok" });
}Cloudflare Workers
テンプレートは以下のコマンドから作成
npm create cloudflare@latestindex.ts:
import { env } from 'cloudflare:workers';
export default {
async scheduled() {
console.log('Cron');
await fetch(`${env.APP_BASE_URL}/api/cron`, {
method: 'POST',
headers: {
Authorization: `Bearer ${env.CRON_SECRET}`,
},
});
},
};認証で保護されたアプリ側のAPIルートにCloudflare Workersから定期的にリクエストする。
wrangler.jsonc:
"triggers": {
"crons": ["0 * * * *"]
}npm run deployをした後にダッシュボードを見ると「トリガーイベント」が追加されている。
tanstack-start
// wrangler.jsonc
"main": "src/server.ts",wrangler.jsoncのmainを@tanstack/react-start/server-entryから任意のファイルパスへ変更
// src/server.ts
import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
import { updateTitleCron } from "./server/mutations/update-title-cron";
const entry = createServerEntry({
fetch(request, env) {
return handler.fetch(request, env);
},
});
export default Object.assign(entry, {
async scheduled() {
await updateTitleCron();
},
});createServerEntry()はwrangler.jsoncのmainに@tanstack/react-start/server-entryと書いていた時の裏側の処理内容cronを実行したい場合、関数名は必ず
scheduledの必要がある。