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=resend requires RESEND_API_KEY and EMAIL_FROM.
  • EMAIL_PROVIDER=mailgun requires MAILGUN_API_KEY, MAILGUN_DOMAIN, and EMAIL_FROM.
  • EMAIL_REPLY_TO is 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

  1. Use Node.js 22.12 or newer and a reachable MySQL 8 database.
  2. Install the exact dependency tree with npm ci in the deployment artifact.
  3. Supply all five MYSQL_* settings, a stable BETTER_AUTH_SECRET, and the public BETTER_AUTH_URL through production configuration or secret storage.
  4. Configure console, Resend, or Mailgun intentionally; use a delivering provider for production auth email.
  5. Confirm a current database backup and a tested restore procedure.
  6. Run npm run db:migrate and npm run verify.
  7. Run npm run build, then supervise npm run start behind the reverse proxy.
  8. Check /api/health, registration, verification, sign-in, sign-out, password reset, protected routes, and administrator access after deployment.
  9. Confirm process monitoring, application logs, database monitoring, and backup alerts.