Bỏ qua menu, vào nội dung chính

Chọn stack kỹ thuật 2026: Next.js, NestJS, Postgres hay gì khác?

Chuyên mục:  Công nghệ
Ngày đăng:  20/04/2026
Thời lượng:  13 phút đọc

Ba ràng buộc quyết định stack cho SME không nằm ở benchmark: ai bảo trì năm thứ ba, hóa đơn GTGT cho hạ tầng, và dữ liệu đặt ở đâu. Kèm cách làm tìm kiếm tiếng Việt không dấu trên PostgreSQL.

Bài so sánh stack thường bàn về hiệu năng. Với dự án cho doanh nghiệp vừa và nhỏ, hiệu năng gần như không bao giờ là ràng buộc thật: một máy chủ tầm trung với PostgreSQL phục vụ dư sức lượng truy cập của một công ty vài chục nhân viên và vài nghìn khách hàng. Ràng buộc thật nằm ở chỗ khác.

Ba ràng buộc quyết định stack cho SME

  1. Ai bảo trì hệ thống ở năm thứ ba. Đội xây ban đầu hiếm khi còn nguyên. Stack càng phổ biến ở thị trường tuyển dụng Việt Nam thì chi phí thay người càng thấp. Một lựa chọn tinh tế mà chỉ ba người trong nước dùng thạo là một khoản nợ, không phải một lợi thế.
  2. Hóa đơn giá trị gia tăng cho chi phí hạ tầng. Dịch vụ nước ngoài trả bằng thẻ quốc tế thường không xuất được hóa đơn GTGT hợp lệ theo quy định Việt Nam, và kế toán sẽ vướng khi hạch toán chi phí. Đây là lý do rất thực tế khiến nhiều doanh nghiệp chọn nhà cung cấp trong nước dù giá niêm yết cao hơn.
  3. Dữ liệu cá nhân đặt ở đâu và ai truy cập được. Nghị định 13/2023/NĐ-CP về bảo vệ dữ liệu cá nhân, có hiệu lực từ 01/07/2023, đặt ra nghĩa vụ với bên xử lý dữ liệu, trong đó có yêu cầu lập hồ sơ đánh giá tác động. Chọn hạ tầng trước, tìm hiểu nghĩa vụ sau là thứ tự sai.

Frontend: Next.js khi nào, và khi nào không cần

Next.js với App Router là lựa chọn mặc định hợp lý cho phần giao diện hướng ra ngoài: trang giới thiệu, trang thương mại, cổng khách hàng. Lý do chính là kết xuất phía máy chủ có sẵn, ảnh hưởng trực tiếp tới việc trang được lập chỉ mục và tới tốc độ hiển thị nội dung đầu tiên trên mạng di động.

Nhưng có một trường hợp Next.js là lựa chọn thừa: bảng điều khiển quản trị nội bộ, chỉ nhân viên đăng nhập mới vào được. Không cần SEO, không cần kết xuất máy chủ. Một ứng dụng một trang dựng bằng Vite chạy nhanh hơn khi phát triển, đóng gói ra tệp tĩnh, và không cần một tiến trình Node chạy thường trực để phục vụ. Ít một thành phần vận hành là ít một chỗ hỏng lúc nửa đêm.

Backend: NestJS, Express hay gộp thẳng vào Next

Quy tắc chọn nhanh: nếu chỉ có một loại client là trình duyệt web, viết luôn API trong Next là đủ và tiết kiệm được một dịch vụ phải triển khai, giám sát và cập nhật.

Tách backend riêng khi rơi vào ít nhất một trong ba tình huống: có nhiều loại client cùng gọi (web, ứng dụng di động, máy bán hàng tại quầy); có tác vụ nền chạy dài như đồng bộ kho hay xuất báo cáo lớn, vốn không hợp với môi trường hàm có giới hạn thời gian chạy; hoặc đội backend là người khác đội frontend và cần vòng đời phát hành riêng.

NestJS đáng giá khi có từ hai lập trình viên backend trở lên: cấu trúc mô-đun và tiêm phụ thuộc dựng sẵn giúp nhiều người sửa cùng lúc mà không giẫm chân nhau. Với một lập trình viên duy nhất, lượng khuôn mẫu phải viết thêm là chi phí thuần túy, và Fastify hoặc Express gọn hơn.

Cơ sở dữ liệu: PostgreSQL gần như luôn là câu trả lời

Với dự án SME, PostgreSQL thắng không phải vì nhanh hơn mà vì nó gộp được nhiều nhu cầu vào một hệ, giúp không phải dựng thêm hạ tầng: kiểu jsonb cho phần dữ liệu cấu trúc thay đổi liên tục, chỉ mục một phần cho các truy vấn lọc theo trạng thái, và bảo mật cấp hàng khi cần chia dữ liệu theo chi nhánh.

Điểm kỹ thuật rất thật: tìm kiếm tiếng Việt không dấu

PostgreSQL không có từ điển tìm kiếm toàn văn cho tiếng Việt như với tiếng Anh. Người dùng Việt lại có thói quen gõ không dấu khi tìm. Cách xử lý phổ biến và ổn định là kết hợp phần mở rộng unaccent để bỏ dấu với pg_trgm để so khớp gần đúng theo cụm ba ký tự, rồi tạo chỉ mục trên biểu thức đã bỏ dấu.

sqlCREATE EXTENSION IF NOT EXISTS unaccent;
CREATE EXTENSION IF NOT EXISTS pg_trgm;

-- unaccent mac dinh khong phai IMMUTABLE nen khong dung truc tiep
-- trong index duoc. Boc lai bang mot ham wrapper.
CREATE OR REPLACE FUNCTION f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS $$
  SELECT public.unaccent('public.unaccent', $1)
$$;

CREATE INDEX idx_kh_ten_trgm
  ON khach_hang
  USING gin (f_unaccent(lower(ho_ten)) gin_trgm_ops);

-- Truy van: go 'nguyen van an' van ra 'Nguyễn Văn An'
SELECT id, ho_ten FROM khach_hang
WHERE f_unaccent(lower(ho_ten)) LIKE '%' || f_unaccent(lower($1)) || '%'
ORDER BY similarity(f_unaccent(lower(ho_ten)), f_unaccent(lower($1))) DESC
LIMIT 20;

MySQL chỉ nên chọn khi có lý do cụ thể: đội đã vận hành MySQL nhiều năm, hoặc hệ thống phải sống chung với một ứng dụng PHP cũ đang dùng chính cơ sở dữ liệu đó. Chọn vì quen thuộc của đội là lý do chính đáng, và thường quan trọng hơn ưu thế kỹ thuật trên giấy.

Lớp truy cập dữ liệu và một cái bẫy về kết nối

Prisma cho trải nghiệm phát triển tốt và bộ công cụ di trú rõ ràng. Drizzle nhẹ hơn, gần SQL hơn, hợp với người muốn kiểm soát câu truy vấn. Cả hai đều dùng được cho dự án SME.

Cái bẫy nằm ở tầng kết nối chứ không ở thư viện. PostgreSQL mặc định giới hạn 100 kết nối đồng thời, trong đó một phần đã dành cho kết nối bảo trì. Khi ứng dụng chạy theo mô hình hàm không máy chủ, mỗi phiên bản hàm mở kết nối riêng và số kết nối có thể vọt lên rất nhanh dưới tải nhẹ. Giải pháp là đặt một bộ gom kết nối như PgBouncer ở giữa, nhưng ở chế độ gom theo giao dịch thì các câu lệnh chuẩn bị sẵn ở phía client sẽ xung đột, và phải tắt tính năng đó trong chuỗi kết nối. Đây là lỗi hay xuất hiện đúng vào ngày có chiến dịch quảng cáo đầu tiên.

Hạ tầng: đặt ứng dụng và cơ sở dữ liệu cùng một vùng

Đây là quy tắc quan trọng hơn mọi lựa chọn nhà cung cấp. Với trang kết xuất phía máy chủ, mỗi lần dựng một trang có thể phát sinh nhiều lượt truy vấn nối tiếp. Nếu ứng dụng chạy ở một vùng và cơ sở dữ liệu ở vùng khác, độ trễ vòng lặp mạng cộng dồn thẳng vào thời gian phản hồi byte đầu tiên. Độ trễ từ Việt Nam sang các trung tâm dữ liệu Singapore thường ở mức vài chục mili giây, còn sang bờ Đông nước Mỹ là hàng trăm mili giây. Nhân với năm sáu lượt truy vấn nối tiếp là đủ để trang cảm thấy chậm rõ rệt dù mã nguồn không có gì sai.

Ba mô hình triển khai hay dùng và nên chọn khi nào:

  • Nền tảng triển khai quốc tế kèm cơ sở dữ liệu quản trị cùng vùng. Nhanh nhất để bắt đầu, ít việc vận hành nhất. Vướng ở khâu hóa đơn GTGT và ở yêu cầu dữ liệu đặt trong nước nếu có.
  • Máy chủ ảo trong nước, chạy container hoặc trình quản lý tiến trình, cơ sở dữ liệu cùng máy hoặc cùng mạng nội bộ. Độ trễ tới người dùng Việt Nam thấp nhất, xuất hóa đơn được, đổi lại phải tự lo bản vá hệ điều hành, sao lưu và giám sát.
  • Kết hợp: giao diện tĩnh đặt trên mạng phân phối nội dung, phần động và cơ sở dữ liệu đặt trong nước. Phức tạp hơn một chút nhưng thường là điểm cân bằng tốt.

Ba lựa chọn đắt tiền nên tránh ở quy mô SME

  1. Kiến trúc nhiều dịch vụ nhỏ. Nó giải quyết bài toán nhiều đội phát hành độc lập. Doanh nghiệp SME có một đội, thường dưới năm người. Cái bạn nhận được là chi phí vận hành nhân lên nhiều lần và những lỗi chỉ xuất hiện khi các dịch vụ gọi nhau. Một khối duy nhất được chia mô-đun rõ ràng là đúng cho quy mô này, và vẫn tách ra được về sau nếu thật sự cần.
  2. GraphQL khi chỉ có đúng một client. Lợi ích của nó là để nhiều client tự chọn dữ liệu cần lấy. Một client thì lợi ích đó bằng không, còn chi phí thì có thật: phải tự lo chống truy vấn lồng quá sâu, chống lấy dữ liệu vượt quyền ở từng trường, và bộ nhớ đệm ở tầng HTTP không dùng được như với REST.
  3. Tự xây hệ thống đăng nhập. Băm mật khẩu đúng cách, đổi mật khẩu, chống dò mật khẩu hàng loạt, xác thực hai lớp, quản lý phiên và thu hồi phiên là một khối lượng công việc lớn và là nơi sai lầm gây hậu quả nặng nhất. Dùng thư viện hoặc dịch vụ đã được kiểm chứng.

Bảng quyết định nhanh

  • Trang giới thiệu, trang thương mại, cổng khách hàng: Next.js App Router, PostgreSQL, triển khai cùng vùng với cơ sở dữ liệu.
  • Bảng điều khiển nội bộ thuần: ứng dụng một trang dựng bằng Vite, API gọn bằng Fastify, PostgreSQL.
  • Có cả web lẫn di động và máy tại quầy: tách backend riêng, cân nhắc NestJS nếu có từ hai backend dev.
  • Phải chạy chung với hệ thống PHP hoặc .NET sẵn có: giữ nguyên cơ sở dữ liệu cũ, viết một lớp API mỏng ở giữa, đừng di trú tất cả trong một lần.

Ba thứ quan trọng hơn cả việc chọn stack

  1. Di trú cơ sở dữ liệu có đánh phiên bản, nằm trong mã nguồn. Sửa lược đồ bằng tay trên máy chủ thật là nguồn gốc của những khác biệt không ai giải thích được giữa môi trường thử và môi trường chạy thật.
  2. Sao lưu đã từng được khôi phục thử. Một bản sao lưu chưa bao giờ khôi phục thử thì chưa phải là bản sao lưu.
  3. Nhật ký tập trung và cảnh báo có người nhận. Nếu lỗi chỉ nằm trong tệp log trên máy chủ và không ai đọc, thì trên thực tế bạn biết về sự cố qua điện thoại của khách hàng.

Tổng kết

Với dự án SME, stack tốt là stack mà người kế nhiệm đọc hiểu trong một tuần, tuyển được người thay thế trong một tháng, và vận hành được bởi một người. Next.js với PostgreSQL đáp ứng cả ba ở thị trường Việt Nam hiện nay, nhưng điều quyết định không phải là cái tên trong danh sách công nghệ mà là ba thói quen kỹ thuật ở mục trên.

Nếu bạn đang cân nhắc giữa hai phương án và muốn một góc nhìn không gắn với việc bán giải pháp, đội ALODEV sẵn sàng trao đổi kỹ thuật trực tiếp.

  • Tech stack
  • Next.js
  • NestJS

Cần tư vấn?
Founder trả lời trong 24 giờ.

Mô tả bài toán, ALODEV tư vấn đúng nghiệp vụ, miễn phí.