← กลับไปหน้าบทความ
คู่มือ

โปรเจกต์ขนาดเล็กไม่จำเป็นต้องแยก CI ออกจาก Vercel เสมอไป แล้วเมื่อไรถึงควร

ทีมบรรณาธิการ linli12 ส.ค. 04:52อัปเดต 12 ส.ค. 04:52อ่าน 6 นาที
โปรเจกต์ขนาดเล็กไม่จำเป็นต้องแยก CI ออกจาก Vercel เสมอไป แล้วเมื่อไรถึงควร
บทความนี้จัดทำเพื่อความรู้ ชื่อธุรกิจ ตัวเลข หรือบทสนทนาที่ไม่มีแหล่งอ้างอิงกำกับเป็นกรณีตัวอย่างเพื่ออธิบายแนวคิด ดูรายละเอียดที่ นโยบายกองบรรณาธิการ

สรุปสั้น ๆ

Vercel มีระบบ build และ deploy อัตโนมัติในตัวอยู่แล้วเมื่อเชื่อมกับ GitHub ทำให้โปรเจกต์เล็กที่ไม่มีขั้นตอนทดสอบซับซ้อนไม่จำเป็นต้องแยก GitHub Actions ออกมาเลยก็ได้ แต่พอทีมเริ่มมีเทสต์หนัก ต้องรัน job ที่ Vercel ทำไม่ได้ (เช่น e2e test, ตรวจสอบ database migration) หรือมีหลาย environment ที่ต้องคุมเงื่อนไข deploy ต่างกัน จุดนั้นคือเส้นแบ่งที่ควรเริ่มแยก CI ออกมาด้วย GitHub Actions

คำถามที่ผมเจอบ่อยจากทีมที่เพิ่งเริ่มใช้ Vercel คือ 'เราต้องตั้ง GitHub Actions ด้วยไหม ในเมื่อ push โค้ดขึ้น GitHub แล้ว Vercel ก็ build และ deploy ให้เองอยู่แล้ว' คำถามนี้ฟังดูตรงไปตรงมา แต่คำตอบไม่ได้ตรงไปตรงมาขนาดนั้น เพราะขึ้นอยู่กับว่าทีมกำลังอยู่ในช่วงไหนของการเติบโต

หลายทีมทำผิดพลาดสองแบบสุดขั้ว แบบแรกคือไม่ตั้ง GitHub Actions เลยทั้งที่โปรเจกต์โตจนต้องการเทสต์ที่ Vercel ทำไม่ได้ ผลคือบั๊กหลุดเข้า production บ่อยเพราะไม่มีอะไรเช็คก่อน deploy จริง แบบที่สองคือตั้ง GitHub Actions ซ้อนทับ Vercel ทั้งที่โปรเจกต์ยังเล็กมาก ผลคือมี pipeline สองชั้นที่ดูแลยาก conflict กันเอง แล้วทีมเสียเวลาไปกับการดูแล infrastructure มากกว่าที่ควร

บทความนี้จะเจาะเงื่อนไขที่ชัดว่าโปรเจกต์แบบไหนยังใช้แค่ Vercel ก็พอ และโปรเจกต์แบบไหนที่ถึงเวลาต้องแยกหน้าที่ระหว่าง CI (GitHub Actions) กับ Deployment (Vercel) ออกจากกัน

Vercel ทำอะไรให้อัตโนมัติอยู่แล้วบ้างเมื่อเชื่อมกับ GitHub

เมื่อเชื่อมโปรเจกต์ GitHub เข้ากับ Vercel ทุกครั้งที่ push โค้ดขึ้น branch ใด ๆ Vercel จะสร้าง Preview Deployment ให้อัตโนมัติ พร้อมรัน `next build` (หรือ build command ที่ตั้งไว้) และรายงานผลกลับมาเป็น status check บน Pull Request เลย ถ้า build ล้มเหลว PR จะขึ้นสถานะแดงทันทีโดยไม่ต้องตั้งค่าอะไรเพิ่ม

นอกจากนี้ Vercel ยังจัดการเรื่อง environment variable ต่อ branch, การ rollback เมื่อ deploy ใหม่มีปัญหา, และการแคช build ให้เองเพื่อให้ build รอบถัดไปเร็วขึ้น สิ่งเหล่านี้คือสิ่งที่ทีมส่วนใหญ่ต้องเขียน workflow เองถ้าใช้ GitHub Actions ล้วน ๆ โดยไม่มี Vercel ช่วย

สำหรับโปรเจกต์ที่งานหลักคือ build แล้ว deploy โดยไม่มีขั้นตอนทดสอบที่ซับซ้อนกว่านี้ ระบบของ Vercel เพียงอย่างเดียวก็ครอบคลุมความต้องการได้เกือบทั้งหมดแล้ว การเพิ่ม GitHub Actions เข้ามาโดยไม่มีเหตุผลชัดเจนจึงมักเป็นการเพิ่มความซับซ้อนโดยไม่ได้ประโยชน์เพิ่ม

สัญญาณที่บอกว่าโปรเจกต์ของคุณยังไม่ต้องแยก CI ออกมา

  • โปรเจกต์มีแค่ build step เดียว ไม่มี unit test หรือมีแต่น้อยมากที่รันเร็วพอจะรวมไว้ใน build command ได้เลย
  • ไม่มี environment ที่ต้อง gate การ deploy ด้วยเงื่อนไขซับซ้อน (เช่นต้องผ่าน manual approval ก่อนขึ้น production)
  • ทีมมีขนาดเล็ก (1-4 คน) และ deploy ผิดแล้ว rollback ได้เร็วโดยไม่กระทบผู้ใช้จำนวนมาก
  • ไม่มีขั้นตอนที่ต้องรันนอกเหนือจาก build เช่น ตรวจสอบ database migration, รัน security scan, หรือ integration test กับระบบภายนอก

Git Integration ปกติของ Vercel กับการให้ Actions เป็นคนสั่ง Deploy เอง ต่างกันตรงไหน

คนส่วนใหญ่เข้าใจว่า 'ใช้ GitHub Actions กับ Vercel' หมายถึงแค่เพิ่มเทสต์เข้าไปคู่กับ deploy ปกติของ Vercel แต่จริง ๆ มีอีกโหมดหนึ่งที่ต่างกันโดยสิ้นเชิงคือให้ Actions เป็นคนสั่ง `vercel deploy` เอง แทนที่จะปล่อยให้ Git Integration ของ Vercel ทำงานตามปกติ สองโหมดนี้แก้ปัญหาคนละแบบ และสับสนกันบ่อยจนทำให้ทีมตั้งค่าซ้อนกันโดยไม่รู้ตัว

โหมด Git Integration แบบปกติทำงานผ่าน webhook ที่ Vercel ผูกกับ repo โดยตรง คุณไม่ต้องเก็บ token หรือเขียน workflow อะไรเพิ่มเลย แค่ push โค้ด Vercel ก็ build และ deploy ให้เองภายในโครงสร้างของ Vercel ทั้งหมด ข้อจำกัดคือคุณควบคุมลำดับขั้นตอนก่อน deploy ได้จำกัด เพราะทุกอย่างเกิดในสภาพแวดล้อมของ Vercel เอง

โหมด Actions-driven คือให้ workflow เป็นคนเรียก Vercel CLI หรือ action สำเร็จรูปเพื่อ deploy เอง ซึ่งต้องปิด auto-deploy ฝั่ง Git Integration ก่อนไม่งั้นจะชนกัน สิ่งที่ได้แลกมาคือควบคุมได้เต็มที่ว่า deploy จะเกิดขึ้นเมื่อไร ต่อจาก job อะไรบ้าง เช่นให้ deploy เกิดหลัง migration สำเร็จเท่านั้น หรือให้ build เกิดใน Actions ครั้งเดียวแล้วส่งผลลัพธ์ที่ build เสร็จแล้วไปให้ Vercel แค่ deploy โดยไม่ต้อง build ซ้ำ

ตัวอย่าง Workflow YAML ที่ Deploy ผ่าน Actions จริง สองแนวทาง

แนวทางแรกที่เขียนง่ายที่สุดคือใช้ action สำเร็จรูปอย่าง `amondnet/vercel-action` ซึ่งห่อคำสั่ง CLI ไว้ให้แล้ว หน้าตา workflow โดยย่อ:

name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

แนวทางที่สองคือใช้ Vercel CLI ตรง ๆ ร่วมกับ `--prebuilt` ซึ่งเหมาะกับทีมที่อยาก build ครั้งเดียวใน Actions แล้วส่งไฟล์ที่ build เสร็จแล้วไปให้ Vercel แค่ deploy โดยไม่ต้อง build ซ้ำอีกรอบ: vercel pull --yes --environment=production --token=$VERCEL_TOKEN
vercel build --prod --token=$VERCEL_TOKEN
vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN
รูปแบบนี้ควบคุมได้ละเอียดกว่า เพราะเปิดโอกาสให้แทรก step เทสต์หรือ migration ระหว่าง `vercel build` กับ `vercel deploy --prebuilt` ได้ ต่างจาก action สำเร็จรูปที่ build กับ deploy ผูกอยู่ในสเต็ปเดียวกัน

Secret ที่ต้องมีก่อน Deploy ผ่าน Actions ได้ และหาแต่ละตัวได้จากไหน

ไม่ว่าจะเลือกแนวทางไหนใน workflow ก่อนหน้า ทั้งคู่ต้องพึ่ง secret สามตัวเหมือนกัน ต้องสร้างไว้ใน GitHub repo settings > Secrets and variables > Actions ก่อนถึงจะรันได้จริง ห้ามใส่ค่าตรง ๆ ลงในไฟล์ YAML เด็ดขาด:

Secretใช้ทำอะไรหาได้จากไหน
VERCEL_TOKENยืนยันตัวตนตอน CLI/action เรียก API ของ VercelVercel Dashboard > Settings > Tokens > สร้าง token ใหม่ กำหนดวันหมดอายุตามนโยบายทีม
VERCEL_ORG_IDบอกว่า deploy เข้าบัญชีหรือทีมไหนของ Vercelรัน `vercel link` ในเครื่อง local แล้วเปิดไฟล์ .vercel/project.json ที่ถูกสร้างขึ้นมาดูค่านี้
VERCEL_PROJECT_IDบอกว่า deploy เข้าโปรเจกต์ไหนในบัญชีนั้นอยู่ในไฟล์ .vercel/project.json เช่นกัน หรือดูจาก Project Settings > General บน Vercel Dashboard

แยก Preview กับ Production Deploy ด้วยเงื่อนไข Branch ยังไง

พฤติกรรมปกติของ Vercel Git Integration คือ push ขึ้น branch ไหนก็ได้ Preview Deployment ที่มี URL เฉพาะของมันเอง ส่วน push หรือ merge เข้า branch ที่ตั้งเป็น production (ปกติคือ main) จึงจะได้ Production Deployment ทับ domain จริง พฤติกรรมนี้เกิดขึ้นเองโดยไม่ต้องตั้งอะไรเพิ่ม

พอย้ายมาใช้ Actions-driven ต้องเขียนเงื่อนไขนี้เอง วิธีที่ทำกันคือใช้ `if: github.ref == 'refs/heads/main'` คั่นไว้ที่ job หรือ step ที่ deploy production แยกจาก job ที่ deploy preview สำหรับ PR ทุกอันให้เรียก `vercel deploy` เฉยๆ (ไม่มี `--prod`) เพื่อได้ preview URL แล้วโพสต์กลับเป็น comment ใน PR ด้วย action แยกอีกตัว ส่วน merge เข้า main เท่านั้นที่เรียก `vercel deploy --prod`

จุดที่พลาดบ่อยคือลืมแยกสอง job นี้ให้ชัด แล้วปล่อยให้ทุก push (ไม่ว่า branch ไหน) เรียก `--prod` เหมือนกันหมด ผลคือ preview branch ที่ยังไม่พร้อมดันทับ production domain ไปโดยไม่ตั้งใจ ต้องเช็คเงื่อนไข branch ให้แน่ใจทุกครั้งก่อนปล่อย workflow เข้า production

ให้เทสต์กับ Lint เป็นด่านก่อนถึง Step Deploy จริง

ข้อดีของการให้ Actions เป็นคน deploy เองคือ deploy step ไม่จำเป็นต้องรันเลยถ้าด่านก่อนหน้าไม่ผ่าน ต่างจาก Git Integration ปกติที่ Vercel จะ build ให้ทุกครั้งไม่ว่าเทสต์จาก Actions จะเขียวหรือแดง (แค่ขึ้น status check แดงคู่กันไป) การตั้ง `needs: [test]` บน job deploy ทำให้ step ที่เรียก `vercel deploy` ถูกข้ามไปเลยถ้า job เทสต์ล้มเหลว

รูปแบบที่ทำกันคือแยก job `test` ให้รัน `npm run lint`, `npm run typecheck`, และ unit test ก่อน แล้วให้ job `deploy` ประกาศ `needs: test` พร้อม `if: success()` เพื่อรันต่อเฉพาะตอนที่ job ก่อนหน้าผ่านครบทุกขั้นตอนเท่านั้น ถ้าอยากให้ job ทั้งสองรันขนานกันเพื่อประหยัดเวลารวม (ไม่รอ lint เสร็จก่อนค่อยเริ่ม build) ก็ทำได้ แต่ deploy step ต้องยังคงรอผลจาก job เทสต์อยู่ดี

ข้อควรระวังคือถ้าใช้ Git Integration ควบคู่ไปด้วย (ไม่ได้ปิด auto-deploy) การตั้งด่านแบบนี้ใน Actions จะไม่มีผลกับ deploy จริงเลย เพราะ Vercel deploy ของมันเองไม่รู้จัก job `test` ใน Actions ต้องเลือกให้ Actions เป็นคนควบคุม deploy เต็มรูปแบบ ด่านนี้ถึงจะบังคับใช้ได้จริง

ทำไม CI Minutes พุ่งเร็วถ้าไม่ตั้ง Build Cache ให้ดี

Vercel Git Integration มี build cache ในตัวอยู่แล้วโดยอัตโนมัติ (เช่น cache ของ `.next/cache` สำหรับ Next.js) ทำให้ build รอบถัดไปเร็วขึ้นเรื่อย ๆ โดยไม่ต้องตั้งอะไรเพิ่ม แต่พอย้าย build ไปทำใน GitHub Actions แทน cache ตัวนี้จะไม่ตามมาด้วย ต้องตั้งเองผ่าน `actions/cache` โดย key ด้วย hash ของ lockfile และ path ของ `.next/cache` มิฉะนั้นทุกรัน workflow จะติดตั้ง dependency และ build ใหม่ทั้งหมดตั้งแต่ศูนย์

ผลของการไม่มี cache ไม่ใช่แค่ deploy ช้าลง แต่ CI minutes ที่ใช้จริงพุ่งขึ้นตามจำนวนครั้งที่ workflow ถูก trigger เพราะ `npm install` และ build เต็มรูปแบบกินเวลานานกว่าการ build ที่มี cache ช่วยหลายเท่าตัว ยิ่งทีมที่ push บ่อยหรือมี workflow trigger ทุก PR ตัวเลขนี้จะสะสมเร็วมาก

ตัวอย่างสมมติ (สำหรับกรอบวิเคราะห์เท่านั้น): ทีมหนึ่งตั้ง workflow deploy ผ่าน Actions โดยลืมตั้ง cache ให้ dependency และ build output แต่ละรันจึงใช้เวลาราวหกถึงเจ็ดนาทีเต็ม ทั้งที่ถ้ามี cache ที่ hit ตรงกันจะเหลือไม่ถึงสองนาที เมื่อทีม push เข้า main และเปิด PR รวมกันหลายสิบครั้งต่อสัปดาห์ ผลต่างของเวลาที่สะสมกลายเป็นตัวเลข CI minutes ที่สูงกว่าที่ควรจะเป็นมาก จนต้องย้อนกลับมาแก้ทีหลัง

ทำแบบนี้แล้วพัง เพราะตั้งค่าซ้อนกันโดยไม่รู้ตัว

เคสที่เจอบ่อยคือทีมตั้ง GitHub Actions ให้ deploy ขึ้น Vercel เองผ่าน CLI (`vercel --prod`) พร้อม ๆ กับที่ Vercel เองก็ตั้ง auto-deploy จาก git push ไว้ด้วย ผลคือมีการ deploy ซ้อนกันสองครั้งในเวลาใกล้กัน บางครั้งเวอร์ชันที่ deploy ทีหลังทับเวอร์ชันที่ผ่านการตรวจสอบจาก Actions ไปแล้ว ทำให้โค้ดที่ยังไม่ผ่านเทสต์หลุดขึ้น production ได้

ทางแก้ที่ทีมส่วนใหญ่ใช้คือเลือกให้ระบบใดระบบหนึ่งเป็นคน deploy จริงเท่านั้น ถ้าเลือกให้ Vercel เป็นคน deploy ให้ GitHub Actions ทำหน้าที่แค่ตรวจสอบและรายงานผล ไม่ต้องเรียก `vercel --prod` เอง ส่วนถ้าเลือกให้ Actions เป็นคนควบคุม deploy ทั้งหมด ต้องปิด auto-deploy ของ Vercel ฝั่ง Git Integration ไม่ให้ทำงานซ้ำกัน

สรุป

คำถามว่า 'ต้องใช้ GitHub Actions ควบคู่กับ Vercel ไหม' ไม่มีคำตอบเดียวที่ใช้ได้ทุกโปรเจกต์ โปรเจกต์เล็กที่มีแค่ build กับ deploy ธรรมดายังใช้ Vercel อย่างเดียวได้สบาย ส่วนโปรเจกต์ที่เริ่มมีเทสต์หนัก database migration หรือขั้นตอนอนุมัติซับซ้อน ถึงเวลาที่ควรแยก CI ออกมาจริงจัง

หลักที่ใช้ตัดสินใจได้ตรงที่สุดคือดูว่ามีขั้นตอนไหนที่ Vercel build pipeline ทำไม่ได้ในตัวมันเองหรือเปล่า ถ้ามี นั่นคือสัญญาณที่ชัดว่าถึงเวลาต้องแบ่งหน้าที่ระหว่างสองระบบให้ชัดเจน แทนที่จะปล่อยให้ซ้อนทับกันจนควบคุมไม่ได้

  • Vercel เพียงอย่างเดียวพอสำหรับโปรเจกต์ที่ไม่มีเทสต์หนักหรือ migration ซับซ้อน
  • แยก GitHub Actions เมื่อมี e2e test, database migration, หรือขั้นตอนอนุมัติที่ต้องควบคุมลำดับ
  • ให้ระบบเดียวเป็นคน deploy จริง อีกระบบทำหน้าที่ตรวจสอบ ป้องกันการ deploy ซ้อนทับ

คำถามที่พบบ่อย

โปรเจกต์เล็กมาก ๆ ยังต้องตั้ง GitHub Actions ไหม

ถ้าโปรเจกต์ยังไม่มีเทสต์ซับซ้อนและไม่มี database migration ที่ต้องควบคุมลำดับ ใช้ระบบ build/deploy อัตโนมัติของ Vercel อย่างเดียวก็เพียงพอแล้ว ไม่จำเป็นต้องเพิ่ม Actions ตั้งแต่วันแรก

ใช้ทั้ง GitHub Actions และ Vercel auto-deploy พร้อมกันได้ไหม

ได้ แต่ต้องกำหนดชัดว่าใครเป็นคน deploy จริง ถ้าปล่อยให้ทั้งสองระบบ deploy เองพร้อมกันจะเกิดการ deploy ซ้อนทับที่ควบคุมลำดับไม่ได้ ควรให้ระบบเดียวเป็นคนควบคุม deploy ส่วนอีกระบบทำหน้าที่ตรวจสอบอย่างเดียว

ควรรัน e2e test ที่ไหน ใน Vercel build หรือ GitHub Actions

ควรรันใน GitHub Actions เพราะ e2e test มักใช้เวลานานและต้องเปิด browser จำลอง ซึ่งไม่เหมาะรวมเข้าไปใน build command ของ Vercel ที่ควรเน้นความเร็วของการ build

database migration ควรรันตอนไหนในสองระบบนี้

ควรรันผ่าน GitHub Actions ก่อนที่ Vercel จะ deploy เวอร์ชันใหม่ เพื่อให้ควบคุมลำดับได้ว่า schema ต้องพร้อมก่อนโค้ดใหม่จะเริ่มทำงาน ไม่ควรปล่อยให้ migration รันพร้อมกับตอน build

ถ้าอยากมี manual approval ก่อน deploy production ทำยังไง

ตั้งผ่าน branch protection rule บน GitHub ให้ status check จาก workflow ที่ต้องการ approval เป็นเงื่อนไขบังคับก่อน merge เข้า branch ที่ผูกกับ production หรือใช้ environment protection rule ของ GitHub Actions ที่รองรับการอนุมัติก่อนรัน job โดยตรง

แยก CI แล้วทำให้เวลา deploy ช้าลงไหม

อาจช้าขึ้นเล็กน้อยถ้า job ใน Actions ต้องรันก่อน Vercel จะ deploy จริง แต่ถ้าออกแบบให้รันขนานกันในส่วนที่ไม่ต้องรอกัน และให้เฉพาะส่วนที่จำเป็นต้องเรียงลำดับเท่านั้นที่รอ ผลกระทบต่อเวลารวมจะน้อยมาก

ทดลองวัดผลโฆษณาเข้า LINE ฟรี 14 วัน

สมัครแล้วสร้างโปรเจกต์ เชื่อม LINE ติดตั้ง Tracking แล้วเริ่มเห็น Funnel จาก Click ถึง Purchase ได้ทันที ไม่ต้องใช้บัตรเครดิต

เริ่มทดลองใช้ฟรี 14 วัน

บทความที่เกี่ยวข้อง

รัน Migration ผ่านฉลุยตอนพัฒนา แต่ทำไมพอ Deploy อัตโนมัติเข้า Production ถึงพังได้ง่ายกว่าที่คิด

รัน Migration ผ่านฉลุยตอนพัฒนา แต่ทำไมพอ Deploy อัตโนมัติเข้า Production ถึงพังได้ง่ายกว่าที่คิด

Supabase CLI ผูกกับ GitHub Actions ได้ทั้ง database migration และ Edge Functions แต่ migration ต่างจาก deploy โค้ดทั่วไปตรงที่แก้ข้อมูลจริงและย้อนกลับไม่ได้เสมอไป บทความนี้เจาะจุดที่ต้องระวังก่อนปล่อยให้ pipeline รันอัตโนมัติ
ทำไมทีมที่ให้ AI Agent เปิด Pull Request เองต้องตั้ง Branch Protection แน่นกว่าทีมทั่วไป

ทำไมทีมที่ให้ AI Agent เปิด Pull Request เองต้องตั้ง Branch Protection แน่นกว่าทีมทั่วไป

Branch Protection ที่เคยพอสำหรับทีมมนุษย์ล้วนอาจไม่พอทันทีที่มี AI agent เปิด PR เองแบบ autonomous บทความนี้เจาะว่าทำไมสมการความเสี่ยงเปลี่ยน และต้องปรับกฎตรงไหนบ้างให้ยังคุมได้จริง
เขียนไฟล์ Instructions ระดับ Repo กับสั่งทุกครั้งในแชท AI ต่างกันตรงไหน

เขียนไฟล์ Instructions ระดับ Repo กับสั่งทุกครั้งในแชท AI ต่างกันตรงไหน

หลายทีมยังสั่ง AI coding agent ซ้ำทุกครั้งในแชทว่าโปรเจกต์ใช้ convention อะไร ทั้งที่เขียนลงไฟล์ instructions ระดับ repo ครั้งเดียวแล้วให้ agent อ่านเองได้ตลอด บทความนี้เจาะความต่างและวิธีเขียนให้ใช้งานได้จริง