Node.js + MySQL
Verge Kit is Cloudflare-first. Workers and D1 remain the default and primary
deployment path. The node-mysql preset is an alternative for applications
that need a self-hosted Node.js runtime and MySQL database.
The generated project is a standalone Astro server. It contains the Node adapter, one MySQL schema and migration tree, and no Wrangler or D1 runtime configuration.
Requirements
- Node.js 22.12 or newer
- npm
- MySQL 8
- A process manager and TLS-terminating reverse proxy for production
Scaffold The Project
Select the preset when creating the application:
npm create vergekit@latest my-app -- --preset node-mysql
cd my-app
npm install
Preset selection happens only during scaffolding. The generated application is a normal Node.js Astro project and does not switch runtimes at startup.
Create The MySQL Database
Create an empty MySQL 8 database and a dedicated application user through your database provider or administration tool. An authorized MySQL administrator can use SQL like this for a local deployment:
CREATE DATABASE vergekit CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'vergekit'@'127.0.0.1' IDENTIFIED BY 'replace-with-a-strong-password';
GRANT ALL PRIVILEGES ON vergekit.* TO 'vergekit'@'127.0.0.1';
Change the allowed host to match where the application connects from. Keep the database off the public internet where possible, and follow your provider’s network and transport-security requirements.
Configure The Environment
Copy the committed template:
cp .env.example .env
Set the local values in .env:
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=vergekit
MYSQL_PASSWORD=replace-with-a-strong-password
MYSQL_DATABASE=vergekit
BETTER_AUTH_SECRET=replace-with-a-long-random-secret
BETTER_AUTH_URL=http://localhost:4321
EMAIL_PROVIDER=console
Generate a Better Auth secret with a cryptographically secure tool, for example:
openssl rand -base64 32
Do not commit .env. MYSQL_PASSWORD may be empty only when the configured
database account has no password. The application, Drizzle Kit, and
administrator command all use these same five MySQL settings.
For production, supply environment variables through the hosting platform,
service manager, or secret store. Existing process variables take precedence
over .env. Keep BETTER_AUTH_SECRET stable, and set BETTER_AUTH_URL to the
exact public HTTPS origin.
Migrate And Initialize
Apply the committed MySQL migrations:
npm run db:migrate
Create the first verified user with the admin role:
npm run init:admin
The administrator command prompts for a name, email, and password, uses the same MySQL settings, and closes its database pool before exiting.
After an intentional change to src/config/schema.ts, generate and review a
new migration before applying it:
npm run db:generate
npm run db:migrate
Use npm run db:studio when you need to inspect the configured database.
Develop And Verify
Start local development:
npm run dev
Before deployment, run the complete check, lint, test, and build pipeline:
npm run verify
Email Options
EMAIL_PROVIDER=console is the non-delivering development default. It prints
auth email content and links to the server log, so treat those logs as
sensitive.
Use an HTTP API provider for delivered email from Node.js:
EMAIL_PROVIDER=resendrequiresRESEND_API_KEYandEMAIL_FROM.EMAIL_PROVIDER=mailgunrequiresMAILGUN_API_KEY,MAILGUN_DOMAIN, andEMAIL_FROM.EMAIL_REPLY_TOis optional for Resend and Mailgun.
The Node.js preset has no Cloudflare Email binding. Do not select the
cloudflare email provider for this deployment target. Store provider API keys
and the Better Auth secret outside source control, and test verification and
password-reset delivery before launch.
Build And Run
Build and start the standalone server through the generated project scripts:
npm run build
npm run start
npm run start runs dist/server/entry.mjs. In production, run that command
under a service manager or hosting supervisor that starts it on boot, restarts
it after failures, preserves logs, and stops it cleanly during deployments.
Keep the application port private behind a reverse proxy. Terminate TLS at the
proxy, forward the original host and protocol, configure appropriate body-size
and timeout limits, and send health checks to /api/health. Keep
BETTER_AUTH_URL aligned with the public HTTPS origin exposed by the proxy.
Backups And Recovery
Back up the MySQL database on a schedule appropriate for the application’s recovery requirements. Keep copies outside the database host, protect them like production data, and test restoration into a separate database. Take or confirm a current backup before applying production schema migrations.
Deployment Checklist
- Use Node.js 22.12 or newer and a reachable MySQL 8 database.
- Install the exact dependency tree with
npm ciin the deployment artifact. - Supply all five
MYSQL_*settings, a stableBETTER_AUTH_SECRET, and the publicBETTER_AUTH_URLthrough production configuration or secret storage. - Configure console, Resend, or Mailgun intentionally; use a delivering provider for production auth email.
- Confirm a current database backup and a tested restore procedure.
- Run
npm run db:migrateandnpm run verify. - Run
npm run build, then supervisenpm run startbehind the reverse proxy. - Check
/api/health, registration, verification, sign-in, sign-out, password reset, protected routes, and administrator access after deployment. - Confirm process monitoring, application logs, database monitoring, and backup alerts.